Decompiled source of BestFFAZones v2.0.0

BestFFAZones.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.Json;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BestFFAZones.Services;
using HarmonyLib;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Network;
using ProjectM.Scripting;
using ProjectM.Terrain;
using Stunlock.Localization;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
using VampireCommandFramework;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Irozer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Only the best of the best")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+850a337f7f7aeba4c9463858d98b5dbd0da4be0b")]
[assembly: AssemblyProduct("BestFFAZones")]
[assembly: AssemblyTitle("BestFFAZones")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BestFFAZones
{
	public static class Core
	{
		public static bool hasInitialized = false;

		public static World Server { get; } = GetWorld("Server") ?? throw new Exception("Server World not found. Did you install the mod on the server?");


		public static EntityManager EntityManager => Server.EntityManager;

		public static ServerGameManager ServerGameManager => Server.GetExistingSystemManaged<ServerScriptMapper>()._ServerGameManager;

		public static PrefabCollectionSystem PrefabCollection { get; } = Server.GetExistingSystemManaged<PrefabCollectionSystem>();


		private static World GetWorld(string name)
		{
			Enumerator<World> enumerator = World.s_AllWorlds.GetEnumerator();
			while (enumerator.MoveNext())
			{
				World current = enumerator.Current;
				if (current.Name == name)
				{
					return current;
				}
			}
			return null;
		}

		public static void LogException(Exception e, [CallerMemberName] string caller = null)
		{
			Debug.LogError(Object.op_Implicit($"[BestFFAZones] Exception in {caller}: {e.Message}\n{e.StackTrace}"));
		}
	}
	[BepInPlugin("com.tonpseudo.BestFFAZones", "BestFFAZones", "1.0.0")]
	public class Plugin : BasePlugin
	{
		private Harmony _harmony;

		public static ManualLogSource Logger;

		public static Plugin Instance { get; private set; }

		public override void Load()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			Instance = this;
			Logger = ((BasePlugin)this).Log;
			string path = Path.Combine(Paths.ConfigPath, "BestFFAZones");
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(46, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("aa.BestFFAZones");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" est en cours de chargement...");
			}
			log.LogInfo(val);
			CommandRegistry.RegisterAll();
			_harmony = new Harmony("com.tonpseudo.BestFFAZones");
			_harmony.PatchAll();
			((BasePlugin)this).Log.LogInfo((object)"BestFFAZones est chargé et prêt !");
		}

		public override bool Unload()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return ((BasePlugin)this).Unload();
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "aa.BestFFAZones";

		public const string PLUGIN_NAME = "BestFFAZones";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace BestFFAZones.Utils
{
	public static class VWorld
	{
		public static World Server
		{
			get
			{
				Enumerator<World> enumerator = World.All.GetEnumerator();
				while (enumerator.MoveNext())
				{
					World current = enumerator.Current;
					if (current.Name == "Server")
					{
						return current;
					}
				}
				return null;
			}
		}

		public static EntityManager ServerEntityManager => Server.EntityManager;
	}
}
namespace BestFFAZones.Services
{
	public class FfaConfig
	{
		public List<string> FfaZones { get; set; } = new List<string>();


		public List<string> RiftT2Zones { get; set; } = new List<string>();


		public List<List<string>> ZoneGroups { get; set; } = new List<List<string>>();

	}
	public static class FfaConfigService
	{
		private static readonly string ConfigFolder = Path.Combine(Paths.ConfigPath, "BestFFAZones");

		private static readonly string ConfigFile = Path.Combine(ConfigFolder, "FfaZoneConfig.json");

		private static HashSet<string> _ffaZoneNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _riftT2ZoneNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static Dictionary<string, int> _zoneGroupMap = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

		public static void Load()
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			try
			{
				if (!Directory.Exists(ConfigFolder))
				{
					Directory.CreateDirectory(ConfigFolder);
				}
				if (!File.Exists(ConfigFile))
				{
					WriteDefaultConfig();
				}
				FfaConfig? ffaConfig = JsonSerializer.Deserialize<FfaConfig>(File.ReadAllText(ConfigFile));
				_ffaZoneNames = new HashSet<string>(ffaConfig?.FfaZones ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
				_riftT2ZoneNames = new HashSet<string>(ffaConfig?.RiftT2Zones ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
				_zoneGroupMap = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
				List<List<string>> list = ffaConfig?.ZoneGroups ?? new List<List<string>>();
				for (int i = 0; i < list.Count; i++)
				{
					foreach (string item in list[i])
					{
						_zoneGroupMap[item] = i;
					}
				}
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(57, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BestFFAZones] ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_ffaZoneNames.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" FFA zone(s), ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_riftT2ZoneNames.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" Rift T2 zone(s), ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" group(s).");
				}
				logger.LogInfo(val);
			}
			catch (Exception e)
			{
				Core.LogException(e, "Load");
			}
		}

		public static bool IsFfaZone(string zoneName)
		{
			return _ffaZoneNames.Contains(zoneName);
		}

		public static bool IsRiftT2Zone(string zoneName)
		{
			return _riftT2ZoneNames.Contains(zoneName);
		}

		public static bool AreSameGroup(string zoneA, string zoneB)
		{
			if (zoneA == null || zoneB == null)
			{
				return false;
			}
			if (!_zoneGroupMap.TryGetValue(zoneA, out var value))
			{
				return false;
			}
			if (!_zoneGroupMap.TryGetValue(zoneB, out var value2))
			{
				return false;
			}
			return value == value2;
		}

		private static void WriteDefaultConfig()
		{
			string contents = JsonSerializer.Serialize(new FfaConfig
			{
				FfaZones = new List<string>
				{
					"9f4bb828842244b9b17ce3d9fd39be6e", "a59283ab08114eb99d930f544fd72cb3", "5a9cec9e790347cfa3c8a567afe1f30b", "737efd4800f347fb9f9727a151d1d038", "f20338c8e2f24165865bcd25e528b084", "4f1ebbbc58454419b2e476d65da49498", "1e6477ec05cb414eb4b39dff87bc293d", "45a43450e1334e6eae86c74f2706ac4c", "de43f46cd3344d7a968d0932e8a689da", "1c8627c360994c698672682d810ebc65",
					"1bacf251032c44e2bb5689122e1d6240", "7bc63b78e0934ee6aeb98df40a4279f4", "00bfdf78f096415ab6ccd7c81d970f79"
				},
				RiftT2Zones = new List<string> { "997217d606c04a3289cff476563b87f7", "70669632e11840f9b3e3c463137a6938", "9d0dd663fdbb4498b6ba2ab501475c6e", "e98a6696ebfe49f1b623ba32bd98f58a", "287a1c1922934560a580d432e224c0b9", "68af6cff2b854e82ac208ca9f59a801f" },
				ZoneGroups = new List<List<string>>
				{
					new List<string> { "1c8627c360994c698672682d810ebc65", "1bacf251032c44e2bb5689122e1d6240", "7bc63b78e0934ee6aeb98df40a4279f4", "00bfdf78f096415ab6ccd7c81d970f79" }
				}
			}, new JsonSerializerOptions
			{
				WriteIndented = true
			});
			File.WriteAllText(ConfigFile, contents);
		}
	}
	public static class PlayerZoneTracker
	{
		private static readonly Dictionary<int, string> _playerCurrentZone = new Dictionary<int, string>();

		public static void Tick()
		{
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//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_0030: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			if (!ZoneService.IsLoaded)
			{
				return;
			}
			EntityManager entityManager = Core.EntityManager;
			EntityQuery val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[3]
			{
				ComponentType.ReadOnly<PlayerCharacter>(),
				ComponentType.ReadOnly<LocalTransform>(),
				ComponentType.ReadOnly<IsConnected>()
			});
			NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val2.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				try
				{
					LocalTransform componentData = ((EntityManager)(ref entityManager)).GetComponentData<LocalTransform>(current);
					PlayerCharacter componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(current);
					NetworkId componentData3 = ((EntityManager)(ref entityManager)).GetComponentData<NetworkId>(current);
					Entity userEntity = componentData2.UserEntity;
					if (!((EntityManager)(ref entityManager)).Exists(userEntity))
					{
						continue;
					}
					int normal_Index = componentData3.Normal_Index;
					float x = componentData.Position.x;
					float z = componentData.Position.z;
					string text = ZoneService.GetZoneAtPosition(x, z)?.Name;
					_playerCurrentZone.TryGetValue(normal_Index, out var value);
					if (text == value)
					{
						continue;
					}
					if (FfaConfigService.AreSameGroup(value, text))
					{
						_playerCurrentZone[normal_Index] = text;
						continue;
					}
					_playerCurrentZone[normal_Index] = text;
					if (text != null)
					{
						if (FfaConfigService.IsFfaZone(text))
						{
							SendMessage(userEntity, "<color=#ff4444>⚔ You have entered a FFA zone. All PvP is enabled!</color>");
						}
						else if (FfaConfigService.IsRiftT2Zone(text))
						{
							SendMessage(userEntity, "<color=#ff9900>⚠ This zone is FFA only during Rift T2 events. PvP will be enabled when a Rift T2 is active!</color>");
						}
					}
					if (value != null)
					{
						if (FfaConfigService.IsFfaZone(value))
						{
							SendMessage(userEntity, "<color=#00ff88>✔ You have left the FFA zone.</color>");
						}
						else if (FfaConfigService.IsRiftT2Zone(value))
						{
							SendMessage(userEntity, "<color=#aaaaaa>You have left the Rift T2 FFA zone.</color>");
						}
					}
				}
				catch (Exception e)
				{
					Core.LogException(e, "Tick");
				}
			}
			val2.Dispose();
			((EntityQuery)(ref val)).Dispose();
		}

		private static void SendMessage(Entity userEntity, string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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)
			//IL_0009: 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_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)
			try
			{
				EntityManager entityManager = Core.EntityManager;
				User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
				FixedString512Bytes val = default(FixedString512Bytes);
				((FixedString512Bytes)(ref val))..ctor(message);
				ServerChatUtils.SendSystemMessageToClient(Core.EntityManager, componentData, ref val);
			}
			catch (Exception e)
			{
				Core.LogException(e, "SendMessage");
			}
		}

		public static void RemovePlayer(int playerId)
		{
			_playerCurrentZone.Remove(playerId);
		}

		public static string GetPlayerZone(int playerId)
		{
			if (!_playerCurrentZone.TryGetValue(playerId, out var value))
			{
				return null;
			}
			return value;
		}
	}
	public class GameZone
	{
		public string Name { get; set; }

		public Entity Entity { get; set; }

		public List<float2> Vertices { get; set; } = new List<float2>();


		public bool ContainsPoint(float px, float pz)
		{
			//IL_0023: 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_0049: 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)
			int count = Vertices.Count;
			if (count < 3)
			{
				return false;
			}
			bool flag = false;
			int index = count - 1;
			for (int i = 0; i < count; i++)
			{
				float x = Vertices[i].x;
				float y = Vertices[i].y;
				float x2 = Vertices[index].x;
				float y2 = Vertices[index].y;
				if (y > pz != y2 > pz && px < (x2 - x) * (pz - y) / (y2 - y) + x)
				{
					flag = !flag;
				}
				index = i;
			}
			return flag;
		}
	}
	public static class ZoneService
	{
		private static List<GameZone> _zones;

		public static bool IsLoaded => _zones != null;

		public static void LoadZones()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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)
			//IL_0035: 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)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_005c: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			_zones = new List<GameZone>();
			EntityManager entityManager = Core.EntityManager;
			EntityQuery val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[2]
			{
				ComponentType.ReadOnly<MapZoneData>(),
				ComponentType.ReadOnly<MapZonePolygonVertexElement>()
			});
			NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val2.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				try
				{
					MapZoneData componentData = ((EntityManager)(ref entityManager)).GetComponentData<MapZoneData>(current);
					DynamicBuffer<MapZonePolygonVertexElement> buffer = ((EntityManager)(ref entityManager)).GetBuffer<MapZonePolygonVertexElement>(current, false);
					GameZone gameZone = new GameZone
					{
						Name = ((object)(LocalizationKey)(ref componentData.Name)).ToString(),
						Entity = current
					};
					for (int i = 0; i < buffer.Length; i++)
					{
						gameZone.Vertices.Add(buffer[i].VertexPos);
					}
					_zones.Add(gameZone);
				}
				catch (Exception e)
				{
					Core.LogException(e, "LoadZones");
				}
			}
			val2.Dispose();
			((EntityQuery)(ref val)).Dispose();
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(31, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[BestFFAZones] ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(_zones.Count);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" zone(s) loaded.");
			}
			logger.LogInfo(val3);
		}

		public static IReadOnlyList<GameZone> GetAllZones()
		{
			return _zones ?? new List<GameZone>();
		}

		public static GameZone GetZoneAtPosition(float px, float pz)
		{
			if (_zones == null)
			{
				return null;
			}
			foreach (GameZone zone in _zones)
			{
				if (zone.ContainsPoint(px, pz))
				{
					return zone;
				}
			}
			return null;
		}
	}
}
namespace BestFFAZones.Patches
{
	[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUserConnected")]
	public static class ServerBootstrapPatch
	{
		public static void Postfix(ServerBootstrapSystem __instance)
		{
			try
			{
				if (!Core.hasInitialized)
				{
					Core.hasInitialized = true;
					ZoneService.LoadZones();
					FfaConfigService.Load();
					Plugin.Logger.LogInfo((object)"[BestFFAZones] Ready.");
				}
			}
			catch (Exception e)
			{
				Core.LogException(e, "Postfix");
			}
		}
	}
	[HarmonyPatch(typeof(TriggerPersistenceSaveSystem), "OnUpdate")]
	public static class GameFramePatch
	{
		private const float CHECK_INTERVAL = 1f;

		private static float _timer;

		public static void Postfix(TriggerPersistenceSaveSystem __instance)
		{
			try
			{
				if (Core.hasInitialized)
				{
					_timer += Time.deltaTime;
					if (!(_timer < 1f))
					{
						_timer = 0f;
						PlayerZoneTracker.Tick();
					}
				}
			}
			catch (Exception e)
			{
				Core.LogException(e, "Postfix");
			}
		}
	}
}
namespace BestFFAZones.Commands
{
	[CommandGroup("ffa", "Gestion des zones FFA")]
	public static class FFACommands
	{
		[Command("reload", null, null, "Recharge la config FFA", null, true)]
		public static void ReloadZones(ChatCommandContext ctx)
		{
			FfaConfigService.Load();
			ctx.Reply("[BestFFAZones] Config rechargée.");
		}

		[Command("list", null, null, "Liste les zones FFA chargées", null, false)]
		public static void ListZones(ChatCommandContext ctx)
		{
			IReadOnlyList<GameZone> allZones = ZoneService.GetAllZones();
			if (allZones.Count == 0)
			{
				ctx.Reply("Aucune zone chargée.");
				return;
			}
			ctx.Reply($"{allZones.Count} zone(s) :");
			foreach (GameZone item in allZones)
			{
				ctx.Reply("  • " + item.Name);
			}
		}

		[Command("zone", null, null, "Affiche le nom/ID de la zone où vous êtes", null, false)]
		public static void WhereAmI(ChatCommandContext ctx)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0030: 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_0039: 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_0040: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = Core.EntityManager;
			Entity senderCharacterEntity = ctx.Event.SenderCharacterEntity;
			if (!((EntityManager)(ref entityManager)).Exists(senderCharacterEntity))
			{
				ctx.Reply("Personnage introuvable.");
				return;
			}
			LocalToWorld componentData = ((EntityManager)(ref entityManager)).GetComponentData<LocalToWorld>(senderCharacterEntity);
			float3 position = ((LocalToWorld)(ref componentData)).Position;
			GameZone zoneAtPosition = ZoneService.GetZoneAtPosition(position.x, position.z);
			if (zoneAtPosition == null)
			{
				ctx.Reply($"Position ({position.x:F0}, {position.z:F0}) — aucune zone détectée.");
			}
			else
			{
				ctx.Reply("Zone : " + zoneAtPosition.Name);
			}
		}
	}
}