Decompiled source of PvPModes v1.0.0

PvpModes.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Entities;
using Jotunn.Managers;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("PvpModes")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PvpModes")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PvpModes;

internal class BountySystem
{
	private class KillRecord
	{
		public string KillerId;

		public string VictimId;

		public DateTime TimestampUtc;
	}

	public class BountyState
	{
		public string PlayerId;

		public DateTime StartUtc;

		public DateTime EndUtc;

		public int Tier;

		public Vector3 LastKnownPosition;
	}

	public class LastHit
	{
		public string VictimName;

		public string AttackerName;

		public float Damage;

		public float Time;
	}

	private readonly List<KillRecord> _kills = new List<KillRecord>();

	private readonly Dictionary<string, BountyState> _activeBounties = new Dictionary<string, BountyState>();

	private readonly Dictionary<long, LastHit> _lastHits = new Dictionary<long, LastHit>();

	private readonly Dictionary<long, float> _reportedDeaths = new Dictionary<long, float>();

	private bool _loadedPersistence;

	private float _nextTimerTick;

	private float _nextPositionSync;

	private float _nextFullSync;

	public static BountySystem Instance { get; } = new BountySystem();


	private string SaveDir => Path.Combine(Paths.ConfigPath, "PvpModes");

	private string SaveFile => Path.Combine(SaveDir, "bounties.txt");

	private string LogDir => Path.Combine(Paths.ConfigPath, "PvpModes", "Logs");

	private TimeSpan KillWindow => TimeSpan.FromMinutes(PvpModes.BountyKillWindowMinutes.Value);

	private TimeSpan BountyDuration => TimeSpan.FromMinutes(PvpModes.BountyDurationMinutes.Value);

	public void Update()
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			if (!_loadedPersistence)
			{
				_loadedPersistence = true;
				LoadBounties();
			}
			if (Time.time >= _nextTimerTick)
			{
				_nextTimerTick = Time.time + 1f;
				UpdateTimers();
			}
			if (Time.time >= _nextPositionSync)
			{
				_nextPositionSync = Time.time + 10f;
				SyncBountyPositions();
			}
			if (Time.time >= _nextFullSync)
			{
				_nextFullSync = Time.time + 30f;
				BroadcastAllBounties();
			}
		}
	}

	private void WriteServerLog(string message)
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			Directory.CreateDirectory(LogDir);
			string path = Path.Combine(LogDir, $"{DateTime.UtcNow:yyyy-MM-dd}.log");
			string text = $"[{DateTime.UtcNow:HH:mm:ss} UTC] {message}";
			File.AppendAllText(path, text + Environment.NewLine);
		}
	}

	private bool IsPlayerOnline(string playerName)
	{
		//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_0030: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNet.instance == (Object)null)
		{
			return false;
		}
		foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
		{
			if (player.m_name == playerName)
			{
				return true;
			}
		}
		return false;
	}

	private static string FormatMessage(string template, string killer = "", string victim = "", string player = "", int tier = 0, int duration = 0, int amount = 0, string item = "")
	{
		return template.Replace("{killer}", killer).Replace("{victim}", victim).Replace("{player}", player)
			.Replace("{tier}", tier.ToString())
			.Replace("{duration}", duration.ToString())
			.Replace("{amount}", amount.ToString())
			.Replace("{item}", item);
	}

	public void RegisterKill(string killerName, string victimName)
	{
		Logger.LogInfo((object)$"[PvpModes SERVER] Config check: trigger={PvpModes.BountyTriggerKillCount.Value}, window={PvpModes.BountyKillWindowMinutes.Value}, duration={PvpModes.BountyDurationMinutes.Value}");
		if (string.IsNullOrWhiteSpace(killerName) || string.IsNullOrWhiteSpace(victimName) || killerName == victimName)
		{
			return;
		}
		DateTime now = DateTime.UtcNow;
		BountyState bounty = GetBounty(victimName);
		ClearBounty(victimName, killed: true);
		_kills.RemoveAll((KillRecord x) => x.KillerId == victimName);
		SaveBounties();
		if (bounty != null)
		{
			int num = Math.Max(1, bounty.Tier) * PvpModes.BountyRewardAmountPerTier.Value;
			string value = PvpModes.BountyRewardItem.Value;
			BountyRpc.SendRewardToPlayer(killerName, value, num);
			_kills.RemoveAll((KillRecord x) => x.KillerId == killerName);
			string message = FormatMessage(PvpModes.MsgBountyReward.Value, killerName, victimName, "", 0, 0, num, value);
			BountyRpc.BroadcastCenterMessage(message);
			WriteServerLog($"REWARD | {killerName} claimed bounty on {victimName} | tier={bounty.Tier} | {num}x {value}");
		}
		_kills.Add(new KillRecord
		{
			KillerId = killerName,
			VictimId = victimName,
			TimestampUtc = now
		});
		CleanupOldKills(now);
		int num2 = _kills.Count((KillRecord x) => x.KillerId == killerName && now - x.TimestampUtc <= KillWindow);
		Logger.LogInfo((object)$"[PvpModes SERVER] Kill registered: {killerName} -> {victimName} | kills={num2}");
		WriteServerLog($"KILL | {killerName} killed {victimName} | kills={num2}");
		BountyRpc.BroadcastCenterMessage(FormatMessage(PvpModes.MsgKillBroadcast.Value, killerName, victimName));
		if (bounty == null && num2 >= PvpModes.BountyTriggerKillCount.Value)
		{
			ActivateOrRefreshBounty(killerName, num2, now);
		}
	}

	private int GetTierFromKills(int kills)
	{
		return (int)Math.Floor(Math.Sqrt(kills));
	}

	private void ActivateOrRefreshBounty(string playerName, int killCount, DateTime now)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: 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)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		int tierFromKills = GetTierFromKills(killCount);
		DateTime dateTime = now.Add(BountyDuration);
		Vector3 playerPosition = GetPlayerPosition(playerName);
		if (!_activeBounties.TryGetValue(playerName, out var value))
		{
			value = new BountyState
			{
				PlayerId = playerName,
				StartUtc = now,
				EndUtc = dateTime,
				Tier = tierFromKills,
				LastKnownPosition = playerPosition
			};
			_activeBounties[playerName] = value;
			Logger.LogInfo((object)("[PvpModes SERVER] BOUNTY ACTIVATED: " + playerName));
			WriteServerLog($"BOUNTY_ACTIVATED | {playerName} | tier={tierFromKills} | end={dateTime:o}");
			BountyRpc.BroadcastCenterMessage(FormatMessage(PvpModes.MsgBountyActivated.Value, "", "", playerName, tierFromKills));
		}
		else
		{
			value.EndUtc = dateTime;
			value.Tier = tierFromKills;
			if (playerPosition != Vector3.zero)
			{
				value.LastKnownPosition = playerPosition;
			}
			Logger.LogInfo((object)("[PvpModes SERVER] BOUNTY REFRESHED: " + playerName));
			WriteServerLog($"BOUNTY_REFRESHED | {playerName} | tier={tierFromKills} | end={dateTime:o}");
			BountyRpc.BroadcastCenterMessage(FormatMessage(PvpModes.MsgBountyRefreshed.Value, "", "", playerName, tierFromKills, PvpModes.BountyDurationMinutes.Value));
		}
		SaveBounties();
		if (IsPlayerOnline(playerName))
		{
			BountyRpc.BroadcastBountyCircle(playerName, active: true, value.LastKnownPosition, tierFromKills, dateTime);
		}
	}

	public void UpdateBountyPositionFromClient(string playerName, Vector3 position)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: 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_0039: Unknown result type (might be due to invalid IL or missing references)
		if (_activeBounties.TryGetValue(playerName, out var value) && !(position == Vector3.zero))
		{
			value.LastKnownPosition = position;
			SaveBounties();
			BountyRpc.BroadcastBountyCircle(playerName, active: true, position, value.Tier, value.EndUtc);
		}
	}

	public void ClearBounty(string playerName, bool killed)
	{
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		if (_activeBounties.Remove(playerName))
		{
			Logger.LogInfo((object)("[PvpModes SERVER] Bounty cleared: " + playerName));
			WriteServerLog($"BOUNTY_CLEARED | {playerName} | killed={killed}");
			if (killed)
			{
				BountyRpc.BroadcastCenterMessage(FormatMessage(PvpModes.MsgBountyCleared.Value, "", "", playerName));
			}
			else
			{
				BountyRpc.BroadcastCenterMessage(FormatMessage(PvpModes.MsgBountyExpired.Value, "", "", playerName));
			}
			SaveBounties();
			BountyRpc.BroadcastBountyCircle(playerName, active: false, Vector3.zero, 0, DateTime.UtcNow);
		}
	}

	public void ResetPlayer(string playerName)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		_activeBounties.Remove(playerName);
		_kills.RemoveAll((KillRecord x) => x.KillerId == playerName || x.VictimId == playerName);
		Logger.LogInfo((object)("[PvpModes SERVER] Full reset: " + playerName));
		WriteServerLog("ADMIN_RESET | " + playerName);
		SaveBounties();
		BountyRpc.BroadcastBountyCircle(playerName, active: false, Vector3.zero, 0, DateTime.UtcNow);
	}

	public BountyState GetBounty(string playerName)
	{
		if (!_activeBounties.TryGetValue(playerName, out var value))
		{
			return null;
		}
		if (DateTime.UtcNow >= value.EndUtc)
		{
			ClearBounty(playerName, killed: false);
			return null;
		}
		return value;
	}

	private void UpdateTimers()
	{
		DateTime now = DateTime.UtcNow;
		foreach (string item in (from x in _activeBounties
			where now >= x.Value.EndUtc
			select x.Key).ToList())
		{
			ClearBounty(item, killed: false);
		}
	}

	private void SyncBountyPositions()
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		DateTime utcNow = DateTime.UtcNow;
		foreach (BountyState item in _activeBounties.Values.ToList())
		{
			if (!(utcNow >= item.EndUtc))
			{
				if (!IsPlayerOnline(item.PlayerId))
				{
					BountyRpc.BroadcastBountyCircle(item.PlayerId, active: false, Vector3.zero, item.Tier, item.EndUtc);
				}
				else
				{
					BountyRpc.BroadcastBountyCircle(item.PlayerId, active: true, item.LastKnownPosition, item.Tier, item.EndUtc);
				}
			}
		}
	}

	private void BroadcastAllBounties()
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		DateTime utcNow = DateTime.UtcNow;
		foreach (BountyState item in _activeBounties.Values.ToList())
		{
			if (!(utcNow >= item.EndUtc))
			{
				if (!IsPlayerOnline(item.PlayerId))
				{
					BountyRpc.BroadcastBountyCircle(item.PlayerId, active: false, Vector3.zero, item.Tier, item.EndUtc);
				}
				else
				{
					BountyRpc.BroadcastBountyCircle(item.PlayerId, active: true, item.LastKnownPosition, item.Tier, item.EndUtc);
				}
			}
		}
	}

	private Vector3 GetPlayerPosition(string playerName)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: 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_0059: Unknown result type (might be due to invalid IL or missing references)
		foreach (Player allPlayer in Player.GetAllPlayers())
		{
			if (allPlayer.GetPlayerName() == playerName)
			{
				return ((Component)allPlayer).transform.position;
			}
		}
		return Vector3.zero;
	}

	private void CleanupOldKills(DateTime now)
	{
		_kills.RemoveAll((KillRecord x) => now - x.TimestampUtc > KillWindow);
	}

	public void SetLastHit(long victimId, string victimName, string attackerName, float damage)
	{
		_lastHits[victimId] = new LastHit
		{
			VictimName = victimName,
			AttackerName = attackerName,
			Damage = damage,
			Time = Time.time
		};
	}

	public LastHit ResolveLastHit(long victimId)
	{
		if (!_lastHits.TryGetValue(victimId, out var value))
		{
			return null;
		}
		if (Time.time - value.Time > 5f)
		{
			return null;
		}
		return value;
	}

	public void TryReportDeath(Player victim)
	{
		long playerID = victim.GetPlayerID();
		if (!_reportedDeaths.TryGetValue(playerID, out var value) || !(Time.time - value < 10f))
		{
			LastHit lastHit = ResolveLastHit(playerID);
			if (lastHit != null)
			{
				_reportedDeaths[playerID] = Time.time;
				Logger.LogInfo((object)("[PvpModes CLIENT] Reporting kill to server: " + lastHit.AttackerName + " -> " + victim.GetPlayerName()));
				BountyRpc.SendKillToServer(lastHit.AttackerName, victim.GetPlayerName());
			}
		}
	}

	private void SaveBounties()
	{
		Directory.CreateDirectory(SaveDir);
		List<string> list = new List<string>();
		foreach (BountyState value in _activeBounties.Values)
		{
			list.Add(string.Join("|", value.PlayerId, value.StartUtc.Ticks, value.EndUtc.Ticks, value.Tier, value.LastKnownPosition.x.ToString(CultureInfo.InvariantCulture), value.LastKnownPosition.y.ToString(CultureInfo.InvariantCulture), value.LastKnownPosition.z.ToString(CultureInfo.InvariantCulture)));
		}
		File.WriteAllLines(SaveFile, list);
	}

	private void LoadBounties()
	{
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		if (!File.Exists(SaveFile))
		{
			return;
		}
		DateTime utcNow = DateTime.UtcNow;
		string[] array = File.ReadAllLines(SaveFile);
		foreach (string text in array)
		{
			string[] array2 = text.Split(new char[1] { '|' });
			if (array2.Length < 7)
			{
				continue;
			}
			string text2 = array2[0];
			if (!long.TryParse(array2[1], out var result) || !long.TryParse(array2[2], out var result2) || !int.TryParse(array2[3], out var result3) || !float.TryParse(array2[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) || !float.TryParse(array2[5], NumberStyles.Float, CultureInfo.InvariantCulture, out var result5) || !float.TryParse(array2[6], NumberStyles.Float, CultureInfo.InvariantCulture, out var result6))
			{
				continue;
			}
			DateTime dateTime = new DateTime(result2, DateTimeKind.Utc);
			if (!(utcNow >= dateTime))
			{
				BountyState bountyState = new BountyState
				{
					PlayerId = text2,
					StartUtc = new DateTime(result, DateTimeKind.Utc),
					EndUtc = dateTime,
					Tier = result3,
					LastKnownPosition = new Vector3(result4, result5, result6)
				};
				_activeBounties[text2] = bountyState;
				Logger.LogInfo((object)("[PvpModes SERVER] Loaded persistent bounty: " + text2));
				WriteServerLog($"BOUNTY_LOADED | {text2} | tier={result3} | end={dateTime:o}");
				if (IsPlayerOnline(text2))
				{
					BountyRpc.BroadcastBountyCircle(text2, active: true, bountyState.LastKnownPosition, result3, dateTime);
				}
			}
		}
		SaveBounties();
	}
}
internal static class BountyRpc
{
	private const string RpcRegisterKill = "PvpModes_RegisterKill";

	private const string RpcBroadcastMessage = "PvpModes_BroadcastMessage";

	private const string RpcBountyCircle = "PvpModes_BountyCircle";

	private const string RpcBountyPosition = "PvpModes_BountyPosition";

	private const string RpcBountyStatusRequest = "PvpModes_BountyStatusRequest";

	private const string RpcBountyStatusResponse = "PvpModes_BountyStatusResponse";

	private const string RpcBountyResetRequest = "PvpModes_BountyResetRequest";

	private const string RpcBountyResetResponse = "PvpModes_BountyResetResponse";

	private const string RpcBountyReward = "PvpModes_BountyReward";

	private static bool _registered;

	private static ZRoutedRpc _registeredInstance;

	private static string _pendingRewardItem;

	private static int _pendingRewardAmount;

	public static void Update()
	{
		EnsureRegistered();
	}

	public static bool EnsureRegistered()
	{
		if (ZRoutedRpc.instance == null)
		{
			_registered = false;
			_registeredInstance = null;
			return false;
		}
		if (_registered && _registeredInstance == ZRoutedRpc.instance)
		{
			return true;
		}
		_registered = false;
		_registeredInstance = ZRoutedRpc.instance;
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_RegisterKill", (Action<long, ZPackage>)RPC_RegisterKill);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BroadcastMessage", (Action<long, ZPackage>)RPC_BroadcastMessage);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BountyCircle", (Action<long, ZPackage>)RPC_BountyCircle);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BountyPosition", (Action<long, ZPackage>)RPC_BountyPosition);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BountyStatusRequest", (Action<long, ZPackage>)RPC_BountyStatusRequest);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BountyStatusResponse", (Action<long, ZPackage>)RPC_BountyStatusResponse);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BountyResetRequest", (Action<long, ZPackage>)RPC_BountyResetRequest);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BountyResetResponse", (Action<long, ZPackage>)RPC_BountyResetResponse);
		ZRoutedRpc.instance.Register<ZPackage>("PvpModes_BountyReward", (Action<long, ZPackage>)RPC_BountyReward);
		_registered = true;
		Logger.LogInfo((object)"[PvpModes] RPC registered successfully");
		return true;
	}

	public static void RequestBountyStatus(string playerName)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		if (!EnsureRegistered())
		{
			Console.instance.Print("[PvpModes] RPC not ready");
			return;
		}
		ZPackage val = new ZPackage();
		val.Write(playerName);
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			SendBountyStatusResponse(ZRoutedRpc.instance.GetServerPeerID(), playerName);
			return;
		}
		ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "PvpModes_BountyStatusRequest", new object[1] { val });
	}

	public static void RequestBountyReset(string playerName)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		if (!EnsureRegistered())
		{
			Console.instance.Print("[PvpModes] RPC not ready");
			return;
		}
		ZPackage val = new ZPackage();
		val.Write(playerName);
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			BountySystem.Instance.ResetPlayer(playerName);
			Console.instance.Print("Reset bounty for " + playerName);
		}
		else
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "PvpModes_BountyResetRequest", new object[1] { val });
		}
	}

	private static void RPC_BountyStatusRequest(long sender, ZPackage pkg)
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			string text = pkg.ReadString();
			ZPackage val = BuildBountyStatusResponse(text);
			Logger.LogInfo((object)$"[PvpModes SERVER] Bounty status request: {text} sender={sender}");
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "PvpModes_BountyStatusResponse", new object[1] { val });
		}
	}

	private static void RPC_BountyStatusResponse(long sender, ZPackage pkg)
	{
		string text = pkg.ReadString();
		string text2;
		if (!pkg.ReadBool())
		{
			text2 = "No bounty for " + text;
		}
		else
		{
			int num = pkg.ReadInt();
			long ticks = pkg.ReadLong();
			TimeSpan timeSpan = new DateTime(ticks, DateTimeKind.Utc) - DateTime.UtcNow;
			if (timeSpan < TimeSpan.Zero)
			{
				timeSpan = TimeSpan.Zero;
			}
			text2 = $"{text} → Tier {num} | Time left: {timeSpan:hh\\:mm\\:ss}";
		}
		Console.instance.Print(text2);
		if ((Object)(object)MessageHud.instance != (Object)null)
		{
			MessageHud.instance.ShowMessage((MessageType)2, text2, 0, (Sprite)null, false);
		}
	}

	private static void RPC_BountyResetRequest(long sender, ZPackage pkg)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Expected O, but got Unknown
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			string text = pkg.ReadString();
			BountySystem.Instance.ResetPlayer(text);
			ZPackage val = new ZPackage();
			val.Write(text);
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "PvpModes_BountyResetResponse", new object[1] { val });
		}
	}

	private static void RPC_BountyResetResponse(long sender, ZPackage pkg)
	{
		string text = pkg.ReadString();
		Console.instance.Print("Reset bounty for " + text);
	}

	private static ZPackage BuildBountyStatusResponse(string playerName)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		ZPackage val = new ZPackage();
		BountySystem.BountyState bounty = BountySystem.Instance.GetBounty(playerName);
		val.Write(playerName);
		val.Write(bounty != null);
		if (bounty != null)
		{
			val.Write(bounty.Tier);
			val.Write(bounty.EndUtc.Ticks);
		}
		return val;
	}

	private static void SendBountyStatusResponse(long targetPeerId, string playerName)
	{
		ZPackage val = BuildBountyStatusResponse(playerName);
		ZRoutedRpc.instance.InvokeRoutedRPC(targetPeerId, "PvpModes_BountyStatusResponse", new object[1] { val });
	}

	public static void SendKillToServer(string killerName, string victimName)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		if (EnsureRegistered())
		{
			ZPackage val = new ZPackage();
			val.Write(killerName);
			val.Write(victimName);
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				BountySystem.Instance.RegisterKill(killerName, victimName);
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "PvpModes_RegisterKill", new object[1] { val });
		}
	}

	public static void SendBountyPositionToServer(string playerName, Vector3 position)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		if (EnsureRegistered() && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()))
		{
			ZPackage val = new ZPackage();
			val.Write(playerName);
			val.Write(position);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "PvpModes_BountyPosition", new object[1] { val });
		}
	}

	public static void BroadcastCenterMessage(string message)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		if (EnsureRegistered())
		{
			ZPackage val = new ZPackage();
			val.Write(message);
			Logger.LogInfo((object)("[PvpModes SERVER] Broadcast message: " + message));
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "PvpModes_BroadcastMessage", new object[1] { val });
		}
	}

	public static void BroadcastBountyCircle(string playerName, bool active, Vector3 position, int tier, DateTime endUtc)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		if (EnsureRegistered())
		{
			ZPackage val = new ZPackage();
			val.Write(playerName);
			val.Write(active);
			val.Write(position);
			val.Write(tier);
			val.Write(endUtc.Ticks);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "PvpModes_BountyCircle", new object[1] { val });
		}
	}

	private static void RPC_RegisterKill(long sender, ZPackage pkg)
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			string text = pkg.ReadString();
			string text2 = pkg.ReadString();
			Logger.LogInfo((object)("[PvpModes SERVER] Kill RPC received: " + text + " -> " + text2));
			BountySystem.Instance.RegisterKill(text, text2);
		}
	}

	private static void RPC_BountyPosition(long sender, ZPackage pkg)
	{
		//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)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			string playerName = pkg.ReadString();
			Vector3 position = pkg.ReadVector3();
			BountySystem.Instance.UpdateBountyPositionFromClient(playerName, position);
		}
	}

	private static void RPC_BroadcastMessage(long sender, ZPackage pkg)
	{
		string text = pkg.ReadString();
		if ((Object)(object)MessageHud.instance != (Object)null)
		{
			MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false);
		}
	}

	private static void RPC_BountyCircle(long sender, ZPackage pkg)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: 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)
		string playerName = pkg.ReadString();
		bool active = pkg.ReadBool();
		Vector3 position = pkg.ReadVector3();
		int tier = pkg.ReadInt();
		long ticks = pkg.ReadLong();
		DateTime endUtc = new DateTime(ticks, DateTimeKind.Utc);
		BountyStatusEffectController.SetLocalBountyStatus(playerName, active, endUtc);
		BountyMapCircle.Set(playerName, active, position, tier, endUtc);
	}

	public static void SendRewardToPlayer(string playerName, string itemPrefabName, int amount)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		if (EnsureRegistered())
		{
			ZPackage val = new ZPackage();
			val.Write(playerName);
			val.Write(itemPrefabName);
			val.Write(amount);
			Logger.LogInfo((object)$"[PvpModes SERVER] Sending reward RPC to {playerName}: {amount}x {itemPrefabName}");
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "PvpModes_BountyReward", new object[1] { val });
		}
	}

	private static void RPC_BountyReward(long sender, ZPackage pkg)
	{
		string text = pkg.ReadString();
		string text2 = pkg.ReadString();
		int num = pkg.ReadInt();
		Logger.LogInfo((object)$"[PvpModes CLIENT] Reward RPC received for {text}: {num}x {text2}");
		if (!((Object)(object)Player.m_localPlayer == (Object)null) && !(Player.m_localPlayer.GetPlayerName() != text))
		{
			Logger.LogInfo((object)("[PvpModes CLIENT] Reward accepted by local player " + Player.m_localPlayer.GetPlayerName()));
			_pendingRewardItem = text2;
			_pendingRewardAmount += num;
			TryGivePendingReward();
		}
	}

	public static void UpdateReward()
	{
		TryGivePendingReward();
	}

	private static void TryGivePendingReward()
	{
		if (string.IsNullOrWhiteSpace(_pendingRewardItem) || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
		{
			return;
		}
		GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(_pendingRewardItem);
		if ((Object)(object)itemPrefab == (Object)null)
		{
			Logger.LogWarning((object)("[PvpModes] Reward prefab not found yet: " + _pendingRewardItem));
			return;
		}
		((Humanoid)Player.m_localPlayer).GetInventory().AddItem(itemPrefab, _pendingRewardAmount);
		if ((Object)(object)MessageHud.instance != (Object)null)
		{
			MessageHud.instance.ShowMessage((MessageType)2, $"Récompense de prime : {_pendingRewardAmount}x {_pendingRewardItem}", 0, (Sprite)null, false);
		}
		_pendingRewardItem = null;
		_pendingRewardAmount = 0;
	}
}
internal static class BountyMapCircle
{
	private class CircleState
	{
		public PinData Pin;

		public bool Active;

		public int Tier;

		public DateTime EndUtc;

		public float NextPositionSend;
	}

	private static readonly Dictionary<string, CircleState> _circles = new Dictionary<string, CircleState>();

	private const float CircleWorldSize = 300f;

	public static void Update()
	{
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		DateTime utcNow = DateTime.UtcNow;
		foreach (KeyValuePair<string, CircleState> item in _circles.ToList())
		{
			if (item.Value.EndUtc <= utcNow)
			{
				Remove(item.Key);
			}
		}
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		string playerName = Player.m_localPlayer.GetPlayerName();
		if (_circles.TryGetValue(playerName, out var value) && value.Active && !(Time.time < value.NextPositionSend))
		{
			value.NextPositionSend = Time.time + 10f;
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			if (value.Pin != null)
			{
				value.Pin.m_pos = position;
				value.Pin.m_name = "RECHERCHÉ: " + playerName;
				SetPinWorldSize(value.Pin, 300f);
			}
			BountyRpc.SendBountyPositionToServer(playerName, position);
		}
	}

	public static void Set(string playerName, bool active, Vector3 position, int tier, DateTime endUtc)
	{
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Minimap.instance == (Object)null)
		{
			return;
		}
		bool flag = (Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.GetPlayerName() == playerName;
		if (!active)
		{
			Remove(playerName);
			return;
		}
		if (flag)
		{
			if (_circles.TryGetValue(playerName, out var value))
			{
				if (value.Pin != null)
				{
					Minimap.instance.RemovePin(value.Pin);
				}
				value.Pin = null;
				value.Active = true;
				value.Tier = tier;
				value.EndUtc = endUtc;
			}
			else
			{
				_circles[playerName] = new CircleState
				{
					Pin = null,
					Active = true,
					Tier = tier,
					EndUtc = endUtc,
					NextPositionSend = 0f
				};
			}
			return;
		}
		string text = "RECHERCHÉ: " + playerName;
		if (_circles.TryGetValue(playerName, out var value2))
		{
			value2.Active = true;
			value2.Tier = tier;
			value2.EndUtc = endUtc;
			if (value2.Pin != null)
			{
				Minimap.instance.RemovePin(value2.Pin);
			}
			PinData pin = Minimap.instance.AddPin(position, (PinType)13, text, false, false, 0L, default(PlatformUserID));
			SetPinWorldSize(pin, 300f);
			value2.Pin = pin;
		}
		else
		{
			PinData pin2 = Minimap.instance.AddPin(position, (PinType)13, text, false, false, 0L, default(PlatformUserID));
			SetPinWorldSize(pin2, 300f);
			_circles[playerName] = new CircleState
			{
				Pin = pin2,
				Active = true,
				Tier = tier,
				EndUtc = endUtc,
				NextPositionSend = 0f
			};
		}
	}

	private static void Remove(string playerName)
	{
		if (_circles.TryGetValue(playerName, out var value))
		{
			if ((Object)(object)Minimap.instance != (Object)null && value.Pin != null)
			{
				Minimap.instance.RemovePin(value.Pin);
			}
			_circles.Remove(playerName);
		}
	}

	private static void SetPinWorldSize(PinData pin, float size)
	{
		FieldInfo field = typeof(PinData).GetField("m_worldSize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field != null)
		{
			field.SetValue(pin, size);
		}
	}
}
internal static class BountyStatusEffectController
{
	private const string EffectName = "SE_PvpModes_Bounty";

	private static readonly int EffectHash = StringExtensionMethods.GetStableHashCode("SE_PvpModes_Bounty");

	private static DateTime _currentEndUtc;

	private static SE_Stats _effectPrefab;

	private static bool _registered;

	private static bool _pendingActive;

	private static DateTime _pendingEndUtc;

	private static string _pendingPlayerName;

	public static void UpdateRegistration()
	{
		if (_registered || (Object)(object)ObjectDB.instance == (Object)null)
		{
			return;
		}
		StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(EffectHash);
		if ((Object)(object)statusEffect != (Object)null)
		{
			_effectPrefab = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null);
			_registered = true;
			return;
		}
		SE_Stats val = (_effectPrefab = ScriptableObject.CreateInstance<SE_Stats>());
		((Object)val).name = "SE_PvpModes_Bounty";
		((StatusEffect)val).m_name = "Recherché";
		((StatusEffect)val).m_tooltip = "Votre position approximative est révélée aux autres joueurs.";
		((StatusEffect)val).m_ttl = 60f;
		Sprite sprite = GetSprite("SoftDeath");
		if ((Object)(object)sprite != (Object)null)
		{
			((StatusEffect)val).m_icon = sprite;
		}
		else
		{
			Logger.LogWarning((object)"[PvpModes] SoftDeath icon not found");
		}
		ObjectDB.instance.m_StatusEffects.Add((StatusEffect)(object)val);
		_registered = true;
		Logger.LogInfo((object)"[PvpModes] Bounty StatusEffect registered");
		if (!string.IsNullOrEmpty(_pendingPlayerName))
		{
			string pendingPlayerName = _pendingPlayerName;
			bool pendingActive = _pendingActive;
			DateTime pendingEndUtc = _pendingEndUtc;
			_pendingPlayerName = null;
			SetLocalBountyStatus(pendingPlayerName, pendingActive, pendingEndUtc);
		}
	}

	public static void SetLocalBountyStatus(string playerName, bool active, DateTime endUtc)
	{
		if (!_registered || (Object)(object)Player.m_localPlayer == (Object)null)
		{
			_pendingPlayerName = playerName;
			_pendingActive = active;
			_pendingEndUtc = endUtc;
		}
		UpdateRegistration();
		if (!_registered || (Object)(object)Player.m_localPlayer == (Object)null || Player.m_localPlayer.GetPlayerName() != playerName)
		{
			return;
		}
		SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan();
		if (!active)
		{
			sEMan.RemoveStatusEffect(EffectHash, false);
			return;
		}
		float num = (float)(endUtc - DateTime.UtcNow).TotalSeconds;
		if (num <= 0f)
		{
			sEMan.RemoveStatusEffect(EffectHash, false);
			return;
		}
		bool flag = sEMan.HaveStatusEffect(EffectHash);
		if (!(_currentEndUtc == endUtc && flag))
		{
			_currentEndUtc = endUtc;
			if (flag)
			{
				sEMan.RemoveStatusEffect(EffectHash, false);
			}
			if ((Object)(object)_effectPrefab != (Object)null)
			{
				((StatusEffect)_effectPrefab).m_ttl = num;
			}
			StatusEffect val = (((Object)(object)_effectPrefab != (Object)null) ? sEMan.AddStatusEffect((StatusEffect)(object)_effectPrefab, true, 0, 0f) : sEMan.AddStatusEffect(EffectHash, true, 0, 0f));
			if ((Object)(object)val != (Object)null)
			{
				val.m_ttl = num;
				val.m_time = 0f;
			}
		}
	}

	private static Sprite GetSprite(string name)
	{
		Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
		foreach (Sprite val in array)
		{
			if (((Object)val).name == name)
			{
				return val;
			}
		}
		return null;
	}
}
internal class BountyStatusCommand : ConsoleCommand
{
	public override string Name => "pvp_bounty";

	public override string Help => "Affiche la bounty d'un joueur. Usage: pvp_bounty nom";

	public override void Run(string[] args)
	{
		if (args.Length < 1)
		{
			Console.instance.Print("Usage: pvp_bounty nom");
		}
		else if (!SynchronizationManager.Instance.PlayerIsAdmin)
		{
			Console.instance.Print("Only server admins can use this command.");
		}
		else
		{
			BountyRpc.RequestBountyStatus(args[0]);
		}
	}
}
internal class BountyResetCommand : ConsoleCommand
{
	public override string Name => "pvp_resetbounty";

	public override string Help => "Reset la bounty et les kills d'un joueur. Usage: pvp_resetbounty nom";

	public override void Run(string[] args)
	{
		if (args.Length < 1)
		{
			Console.instance.Print("Usage: pvp_resetbounty nom");
		}
		else if (!SynchronizationManager.Instance.PlayerIsAdmin)
		{
			Console.instance.Print("Only server admins can use this command.");
		}
		else
		{
			BountyRpc.RequestBountyReset(args[0]);
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
internal static class TrackLastHit
{
	private static void Prefix(Character __instance, HitData hit)
	{
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if (val == null)
		{
			return;
		}
		Character attacker = hit.GetAttacker();
		Player val2 = (Player)(object)((attacker is Player) ? attacker : null);
		if (val2 != null && !((Object)(object)val2 == (Object)(object)val))
		{
			float health = ((Character)val).GetHealth();
			float totalDamage = hit.GetTotalDamage();
			BountySystem.Instance.SetLastHit(val.GetPlayerID(), val.GetPlayerName(), val2.GetPlayerName(), totalDamage);
			if (totalDamage >= health)
			{
				BountySystem.Instance.TryReportDeath(val);
			}
		}
	}
}
[BepInPlugin("dzk.pvpmodes", "PvpModes", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal class PvpModes : BaseUnityPlugin
{
	public const string PluginGUID = "dzk.pvpmodes";

	public const string PluginName = "PvpModes";

	public const string PluginVersion = "1.0.0";

	public static PvpModes Instance;

	public static CustomLocalization Localization;

	public static ConfigEntry<int> BountyTriggerKillCount;

	public static ConfigEntry<int> BountyKillWindowMinutes;

	public static ConfigEntry<int> BountyDurationMinutes;

	public static ConfigEntry<string> BountyRewardItem;

	public static ConfigEntry<int> BountyRewardAmountPerTier;

	public static ConfigEntry<string> MsgKillBroadcast;

	public static ConfigEntry<string> MsgBountyActivated;

	public static ConfigEntry<string> MsgBountyRefreshed;

	public static ConfigEntry<string> MsgBountyCleared;

	public static ConfigEntry<string> MsgBountyExpired;

	public static ConfigEntry<string> MsgBountyReward;

	private FileSystemWatcher _configWatcher;

	private DateTime _lastConfigReloadUtc;

	private void Awake()
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Expected O, but got Unknown
		Instance = this;
		Localization = LocalizationManager.Instance.GetLocalization();
		SetupConfig();
		SetupConfigWatcher();
		Logger.LogInfo((object)"PvpModes is loading...");
		Harmony val = new Harmony("dzk.pvpmodes");
		val.PatchAll();
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new BountyStatusCommand());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new BountyResetCommand());
		Logger.LogInfo((object)"PvpModes loaded successfully.");
	}

	private void Update()
	{
		BountyRpc.Update();
		BountySystem.Instance.Update();
		BountyMapCircle.Update();
		BountyStatusEffectController.UpdateRegistration();
		BountyRpc.UpdateReward();
	}

	private void SetupConfig()
	{
		BountyTriggerKillCount = ((BaseUnityPlugin)this).Config.Bind<int>("Bounty", "TriggerKillCount", 3, "Number of player kills required to activate a bounty.");
		BountyKillWindowMinutes = ((BaseUnityPlugin)this).Config.Bind<int>("Bounty", "KillWindowMinutes", 180, "Time window in minutes during which kills are counted for bounty activation.");
		BountyDurationMinutes = ((BaseUnityPlugin)this).Config.Bind<int>("Bounty", "DurationMinutes", 60, "How long the bounty stays active, in minutes.");
		BountyRewardItem = ((BaseUnityPlugin)this).Config.Bind<string>("Bounty", "RewardItem", "Coins", "Prefab name of the item rewarded when killing a bounty player.");
		BountyRewardAmountPerTier = ((BaseUnityPlugin)this).Config.Bind<int>("Bounty", "RewardAmountPerTier", 100, "Reward amount per bounty tier.");
		MsgKillBroadcast = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "KillBroadcast", "{killer} a tué {victim}", "Broadcast when a player kills another player.");
		MsgBountyActivated = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "BountyActivated", "{player} est maintenant recherché ! Tier {tier}", "Broadcast when a bounty starts.");
		MsgBountyRefreshed = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "BountyRefreshed", "{player} reste recherché ! Tier {tier} | Timer remis à {duration} min.", "Broadcast when bounty timer refreshes.");
		MsgBountyCleared = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "BountyCleared", "{player} n'est plus recherché.", "Broadcast when a bounty is cleared.");
		MsgBountyExpired = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "BountyExpired", "La prime de {player} a expiré.", "Broadcast when a bounty expires.");
		MsgBountyReward = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "BountyReward", "{killer} a éliminé le joueur recherché {victim} et gagne {amount}x {item} !", "Broadcast when a bounty is claimed.");
	}

	private void SetupConfigWatcher()
	{
		string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
		string directoryName = Path.GetDirectoryName(configFilePath);
		string fileName = Path.GetFileName(configFilePath);
		if (!string.IsNullOrWhiteSpace(directoryName) && !string.IsNullOrWhiteSpace(fileName))
		{
			_configWatcher = new FileSystemWatcher(directoryName, fileName)
			{
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
				EnableRaisingEvents = true
			};
			_configWatcher.Changed += OnConfigFileChanged;
			_configWatcher.Created += OnConfigFileChanged;
			_configWatcher.Renamed += OnConfigFileChanged;
			Logger.LogInfo((object)"[PvpModes] Config watcher enabled");
		}
	}

	private void OnConfigFileChanged(object sender, FileSystemEventArgs e)
	{
		DateTime utcNow = DateTime.UtcNow;
		if ((utcNow - _lastConfigReloadUtc).TotalMilliseconds < 500.0)
		{
			return;
		}
		_lastConfigReloadUtc = utcNow;
		try
		{
			((BaseUnityPlugin)this).Config.Reload();
			Logger.LogInfo((object)"[PvpModes] Config reloaded");
			Logger.LogInfo((object)("[PvpModes] Bounty config: " + $"trigger={BountyTriggerKillCount.Value}, " + $"window={BountyKillWindowMinutes.Value}, " + $"duration={BountyDurationMinutes.Value}, " + $"reward={BountyRewardAmountPerTier.Value}x {BountyRewardItem.Value}"));
		}
		catch (Exception arg)
		{
			Logger.LogWarning((object)$"[PvpModes] Failed to reload config: {arg}");
		}
	}

	private void OnDestroy()
	{
		if (_configWatcher != null)
		{
			_configWatcher.Changed -= OnConfigFileChanged;
			_configWatcher.Created -= OnConfigFileChanged;
			_configWatcher.Renamed -= OnConfigFileChanged;
			_configWatcher.Dispose();
			_configWatcher = null;
		}
	}
}