Decompiled source of LycansRoles v1.0.2

plugins/LycansMod.Roles.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using Fusion;
using LycansMods.Shared;
using Microsoft.CodeAnalysis;
using On;
using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("LycansMod.Roles")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LycansMod.Roles")]
[assembly: AssemblyTitle("LycansMod.Roles")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[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 LycansMods.Shared
{
	public static class ActionRequests
	{
		private const string HandlersKey = "lycans.mods.actions.handlers";

		private const string SendKey = "lycans.mods.actions.send";

		public static void Register(string action, Action<PlayerController, int, Vector3> handler)
		{
			Handlers()[ModProposals.Hash(action)] = handler;
		}

		public static bool Request(string action, PlayerController actor, int value, Vector3 position = default(Vector3))
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return Send(broadcast: false, action, actor, value, position);
		}

		public static bool Broadcast(string action, PlayerController actor, int value, Vector3 position = default(Vector3))
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return Send(broadcast: true, action, actor, value, position);
		}

		public static bool ShouldSendFrom(PlayerController actor)
		{
			if ((Object)(object)actor != (Object)null && ((SimulationBehaviour)actor).HasInputAuthority && (Object)(object)((SimulationBehaviour)actor).Runner != (Object)null)
			{
				return ((SimulationBehaviour)actor).Runner.IsForward;
			}
			return false;
		}

		public static void PublishSender(Action<bool, int, int, int, Vector3> send)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.actions.send", send);
		}

		public static void Dispatch(int hash, int actorIndex, int value, Vector3 position)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (!Handlers().TryGetValue(hash, out var value2))
			{
				Log.Warning("[ActionRequests] Action inconnue (" + hash + ") : mod absent chez ce joueur ?");
				return;
			}
			PlayerController actor = null;
			PlayerRegistry.ForEach((Action<PlayerController>)delegate(PlayerController p)
			{
				if ((Object)(object)actor == (Object)null && (Object)(object)p != (Object)null && p.Index == actorIndex)
				{
					actor = p;
				}
			});
			try
			{
				value2(actor, value, position);
			}
			catch (Exception ex)
			{
				Log.Error("[ActionRequests] Action en erreur : " + ex);
			}
		}

		private static bool Send(bool broadcast, string action, PlayerController actor, int value, Vector3 position)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (!(AppDomain.CurrentDomain.GetData("lycans.mods.actions.send") is Action<bool, int, int, int, Vector3> action2))
			{
				Log.Warning("[ActionRequests] « " + action + " » ignorée : mod_core absent.");
				return false;
			}
			action2(broadcast, ModProposals.Hash(action), ((Object)(object)actor != (Object)null) ? actor.Index : (-1), value, position);
			return true;
		}

		private static Dictionary<int, Action<PlayerController, int, Vector3>> Handlers()
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.actions.handlers") is Dictionary<int, Action<PlayerController, int, Vector3>> result)
			{
				return result;
			}
			Dictionary<int, Action<PlayerController, int, Vector3>> dictionary = new Dictionary<int, Action<PlayerController, int, Vector3>>();
			AppDomain.CurrentDomain.SetData("lycans.mods.actions.handlers", dictionary);
			return dictionary;
		}
	}
	public static class AdminCommands
	{
		private const string Key = "lycans.mods.admin.commands";

		public static void Register(string category, string label, Action run, Func<bool> available = null)
		{
			List<object[]> list = All();
			lock (list)
			{
				list.Add(new object[4] { category, label, run, available });
			}
		}

		public static List<object[]> All()
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.admin.commands") is List<object[]> result)
			{
				return result;
			}
			List<object[]> list = new List<object[]>();
			AppDomain.CurrentDomain.SetData("lycans.mods.admin.commands", list);
			return list;
		}
	}
	public static class AudioBank
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static hook_Spawned <>9__3_0;

			internal void <LoadEmbedded>b__3_0(orig_Spawned orig, GameManager self)
			{
				orig.Invoke(self);
				if (_loaded)
				{
					return;
				}
				_loaded = true;
				string[] manifestResourceNames = _assembly.GetManifestResourceNames();
				foreach (string text in manifestResourceNames)
				{
					if (text.StartsWith("LycansAudio.", StringComparison.Ordinal))
					{
						((MonoBehaviour)self).StartCoroutine(Load(text));
					}
				}
			}
		}

		public const string ResourcePrefix = "LycansAudio.";

		private static Assembly _assembly;

		private static bool _loaded;

		public static void LoadEmbedded(Assembly assembly)
		{
			//IL_0028: 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_0033: Expected O, but got Unknown
			if (_assembly != null)
			{
				return;
			}
			_assembly = assembly;
			object obj = <>c.<>9__3_0;
			if (obj == null)
			{
				hook_Spawned val = delegate(orig_Spawned orig, GameManager self)
				{
					orig.Invoke(self);
					if (!_loaded)
					{
						_loaded = true;
						string[] manifestResourceNames = _assembly.GetManifestResourceNames();
						foreach (string text in manifestResourceNames)
						{
							if (text.StartsWith("LycansAudio.", StringComparison.Ordinal))
							{
								((MonoBehaviour)self).StartCoroutine(Load(text));
							}
						}
					}
				};
				<>c.<>9__3_0 = val;
				obj = (object)val;
			}
			GameManager.Spawned += (hook_Spawned)obj;
		}

		private static IEnumerator Load(string resource)
		{
			string fileName = resource.Substring("LycansAudio.".Length);
			string text2;
			try
			{
				string text = Path.Combine(Path.GetTempPath(), "LycansModsAudio");
				Directory.CreateDirectory(text);
				text2 = Path.Combine(text, fileName);
				using Stream stream = _assembly.GetManifestResourceStream(resource);
				using FileStream destination = File.Create(text2);
				stream.CopyTo(destination);
			}
			catch (Exception ex)
			{
				Log.Error("[AudioBank] Extraction impossible de " + fileName + " : " + ex.Message);
				yield break;
			}
			string name = Path.GetFileNameWithoutExtension(fileName);
			bool split = name.EndsWith("__split", StringComparison.OrdinalIgnoreCase);
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip("file://" + text2.Replace("\\", "/"), TypeOf(text2));
			try
			{
				if (split)
				{
					DownloadHandler downloadHandler = request.downloadHandler;
					DownloadHandlerAudioClip val = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null);
					if (val != null)
					{
						val.streamAudio = false;
					}
				}
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					Log.Error("[AudioBank] Lecture impossible de " + fileName + " : " + request.error);
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(request);
				AudioManager instance = AudioManager.Instance;
				if ((Object)(object)content == (Object)null || instance?.soundBank?.dictionary == null)
				{
					Log.Error("[AudioBank] " + fileName + " : son ou banque de sons du jeu indisponible.");
					yield break;
				}
				if (split)
				{
					AddSplit(instance, content, name.Substring(0, name.Length - "__split".Length).ToUpperInvariant());
					yield break;
				}
				string text3 = (((Object)content).name = name.ToUpperInvariant());
				instance.soundBank.dictionary[text3] = content;
				Log.Info("[AudioBank] Son « " + text3 + " » ajouté.");
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static void AddSplit(AudioManager audio, AudioClip clip, string baseKey)
		{
			int num = Math.Max(1, clip.channels);
			float[] array = new float[clip.samples * num];
			clip.GetData(array, 0);
			List<int[]> list = DetectSegments(array, num, clip.frequency);
			if (list.Count == 0)
			{
				((Object)clip).name = baseKey;
				audio.soundBank.dictionary[baseKey] = clip;
				Log.Warning("[AudioBank] « " + baseKey + " » : aucun segment, son entier ajouté.");
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				int num2 = list[i][0];
				int num3 = list[i][1] - list[i][0];
				float[] array2 = new float[num3 * num];
				Array.Copy(array, num2 * num, array2, 0, num3 * num);
				string text = baseKey + "_" + (i + 1);
				AudioClip val = AudioClip.Create(text, num3, num, clip.frequency, false);
				val.SetData(array2, 0);
				audio.soundBank.dictionary[text] = val;
			}
			Log.Info("[AudioBank] « " + baseKey + " » découpé en " + list.Count + " son(s).");
		}

		private static List<int[]> DetectSegments(float[] data, int channels, int frequency)
		{
			int num = data.Length / channels;
			float num2 = 0f;
			foreach (float num3 in data)
			{
				num2 = Mathf.Max(num2, Mathf.Abs(num3));
			}
			float num4 = Mathf.Max(0.02f, num2 * 0.08f);
			int num5 = Mathf.Max(1, (int)((float)frequency * 0.12f));
			int minSegment = Mathf.Max(1, (int)((float)frequency * 0.05f));
			int pad = (int)((float)frequency * 0.02f);
			List<int[]> list = new List<int[]>();
			bool flag = false;
			int start = 0;
			int num6 = 0;
			for (int j = 0; j < num; j++)
			{
				float num7 = 0f;
				for (int k = 0; k < channels; k++)
				{
					num7 = Mathf.Max(num7, Mathf.Abs(data[j * channels + k]));
				}
				if (num7 >= num4)
				{
					if (!flag)
					{
						flag = true;
						start = j;
					}
					num6 = 0;
				}
				else if (flag && ++num6 >= num5)
				{
					AddSegment(list, start, j - num6 + 1, num, minSegment, pad);
					flag = false;
				}
			}
			if (flag)
			{
				AddSegment(list, start, num, num, minSegment, pad);
			}
			return list;
		}

		private static void AddSegment(List<int[]> segments, int start, int end, int frames, int minSegment, int pad)
		{
			start = Math.Max(0, start - pad);
			end = Math.Min(frames, end + pad);
			if (end - start >= minSegment)
			{
				segments.Add(new int[2] { start, end });
			}
		}

		private static AudioType TypeOf(string path)
		{
			return (AudioType)(Path.GetExtension(path).ToLowerInvariant() switch
			{
				".mp3" => 13, 
				".ogg" => 14, 
				".wav" => 20, 
				_ => 0, 
			});
		}
	}
	public enum CanMoveDecision
	{
		NoOpinion,
		Allow,
		Deny
	}
	public static class CanMoveRules
	{
		public const string Method = "PlayerController.IsCanMove";

		private const string DecisionKey = "decision";

		private static readonly object[] Boxed = new object[3] { 0, 1, 2 };

		public static void Decide(int priority, string owner, Func<PlayerController, CanMoveDecision> step)
		{
			HookPipeline.Register("PlayerController.IsCanMove", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Expected O, but got Unknown
				CanMoveDecision canMoveDecision = step((PlayerController)data["player"]);
				if (canMoveDecision != CanMoveDecision.NoOpinion)
				{
					data["decision"] = Boxed[(int)canMoveDecision];
					data["cancel"] = HookPipeline.True;
				}
			});
		}

		public static IDictionary<string, object> NewData()
		{
			return new Dictionary<string, object>();
		}

		public static int Run(IDictionary<string, object> data, PlayerController player)
		{
			data["player"] = player;
			data["decision"] = Boxed[0];
			data["cancel"] = HookPipeline.False;
			HookPipeline.RunBefore("PlayerController.IsCanMove", data);
			return (int)data["decision"];
		}
	}
	public static class CursorControl
	{
		private const string CountKey = "lycans.mods.cursor.count";

		private const string PreviousKey = "lycans.mods.cursor.previous";

		private static readonly object Lock = new object();

		private static int Count
		{
			get
			{
				object data = AppDomain.CurrentDomain.GetData("lycans.mods.cursor.count");
				if (data is int)
				{
					return (int)data;
				}
				return 0;
			}
		}

		public static void Request()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			lock (Lock)
			{
				int count = Count;
				if (count == 0)
				{
					AppDomain.CurrentDomain.SetData("lycans.mods.cursor.previous", new bool[2]
					{
						Cursor.visible,
						(int)Cursor.lockState == 1
					});
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
					Log.Info("[CursorControl] Curseur libéré (premier panneau ouvert).");
				}
				AppDomain.CurrentDomain.SetData("lycans.mods.cursor.count", count + 1);
			}
		}

		public static void Release()
		{
			lock (Lock)
			{
				int num = Math.Max(0, Count - 1);
				AppDomain.CurrentDomain.SetData("lycans.mods.cursor.count", num);
				if (num == 0)
				{
					if (AppDomain.CurrentDomain.GetData("lycans.mods.cursor.previous") is bool[] array && array.Length == 2)
					{
						Cursor.visible = array[0];
						Cursor.lockState = (CursorLockMode)(array[1] ? 1 : 0);
					}
					Log.Info("[CursorControl] Curseur restauré (dernier panneau fermé).");
				}
			}
		}
	}
	public static class CustomAnimations
	{
		private const string DefinitionsKey = "lycans.mods.animations.definitions";

		private const string AnimatorsKey = "lycans.mods.animations.animators";

		private const string PlayKey = "lycans.mods.animations.play";

		private const string StopKey = "lycans.mods.animations.stop";

		private const string PlayingKey = "lycans.mods.animations.playing";

		public static IEnumerable<string> Ids => Definitions().Keys;

		public static void Define(string id, AnimationClip[] clips, int holdIndex = -1)
		{
			if (string.IsNullOrEmpty(id) || clips == null || clips.Length == 0 || Array.IndexOf(clips, null) >= 0)
			{
				Log.Warning("[CustomAnimations] « " + id + " » ignorée : clip manquant.");
				return;
			}
			Definitions()[id] = new object[2] { clips, holdIndex };
		}

		public static void Play(PlayerController player, string id)
		{
			if ((Object)(object)player != (Object)null && AppDomain.CurrentDomain.GetData("lycans.mods.animations.play") is Action<PlayerController, string> action)
			{
				action(player, id);
			}
		}

		public static void Stop(PlayerController player)
		{
			if ((Object)(object)player != (Object)null && AppDomain.CurrentDomain.GetData("lycans.mods.animations.stop") is Action<PlayerController> action)
			{
				action(player);
			}
		}

		public static bool IsPlaying(PlayerController player)
		{
			if ((Object)(object)player != (Object)null && AppDomain.CurrentDomain.GetData("lycans.mods.animations.playing") is Func<PlayerController, bool> func)
			{
				return func(player);
			}
			return false;
		}

		public static void RegisterExtraAnimator(string key, Func<PlayerController, Animator> animator)
		{
			Animators()[key] = animator;
		}

		public static void PublishImplementation(Action<PlayerController, string> play, Action<PlayerController> stop, Func<PlayerController, bool> playing)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.animations.play", play);
			AppDomain.CurrentDomain.SetData("lycans.mods.animations.stop", stop);
			AppDomain.CurrentDomain.SetData("lycans.mods.animations.playing", playing);
		}

		public static SortedDictionary<string, object[]> Definitions()
		{
			return GetOrCreate<SortedDictionary<string, object[]>>("lycans.mods.animations.definitions");
		}

		public static Dictionary<string, Func<PlayerController, Animator>> Animators()
		{
			return GetOrCreate<Dictionary<string, Func<PlayerController, Animator>>>("lycans.mods.animations.animators");
		}

		private static T GetOrCreate<T>(string key) where T : class, new()
		{
			if (AppDomain.CurrentDomain.GetData(key) is T result)
			{
				return result;
			}
			T val = new T();
			AppDomain.CurrentDomain.SetData(key, val);
			return val;
		}
	}
	public static class CustomEffects
	{
		private const string DefinitionsKey = "lycans.mods.effects.definitions";

		private const string ApplyKey = "lycans.mods.effects.apply";

		public static void Define(string key, Type effectType, Func<bool> enabled, Func<float> duration, Action<PlayerController, bool> onDrink = null)
		{
			Definitions()[key] = new object[4] { effectType, enabled, duration, onDrink };
		}

		public static void Apply(string key, PlayerController target, float duration)
		{
			if ((Object)(object)target != (Object)null && AppDomain.CurrentDomain.GetData("lycans.mods.effects.apply") is Action<string, PlayerController, float> action)
			{
				action(key, target, duration);
			}
		}

		public static void PublishApply(Action<string, PlayerController, float> apply)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.effects.apply", apply);
		}

		public static SortedDictionary<string, object[]> Definitions()
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.effects.definitions") is SortedDictionary<string, object[]> result)
			{
				return result;
			}
			SortedDictionary<string, object[]> sortedDictionary = new SortedDictionary<string, object[]>(StringComparer.Ordinal);
			AppDomain.CurrentDomain.SetData("lycans.mods.effects.definitions", sortedDictionary);
			return sortedDictionary;
		}
	}
	public sealed class PotionPoolContext
	{
		private readonly IDictionary<string, object> _data;

		public List<Effect> NativeEffects => (List<Effect>)_data["native"];

		internal PotionPoolContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class PotionRules
	{
		public const string Method = "GameManager.GenerateEffects";

		public static void Before(int priority, string owner, Action<PotionPoolContext> step)
		{
			HookPipeline.Register("GameManager.GenerateEffects", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				step(new PotionPoolContext(data));
			});
		}

		public static IDictionary<string, object> NewData(List<Effect> native)
		{
			return new Dictionary<string, object>
			{
				["native"] = native,
				["cancel"] = HookPipeline.False
			};
		}
	}
	public static class CustomItems
	{
		private const string DefinitionsKey = "lycans.mods.items.definitions";

		private const string SpawnKey = "lycans.mods.items.spawn";

		public static void Define(string key, Type itemType, Func<GameObject> visual, float visualScale, Func<bool> enabled)
		{
			Definitions()[key] = new object[4] { itemType, visual, visualScale, enabled };
		}

		public static Item Spawn(string key, Vector3 position, Quaternion rotation)
		{
			//IL_001c: 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)
			if (!(AppDomain.CurrentDomain.GetData("lycans.mods.items.spawn") is Func<string, Vector3, Quaternion, Item> func))
			{
				return null;
			}
			return func(key, position, rotation);
		}

		public static string KeyOf(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			foreach (KeyValuePair<string, object[]> item2 in Definitions())
			{
				if ((Type)item2.Value[0] == ((object)item).GetType())
				{
					return item2.Key;
				}
			}
			return null;
		}

		public static void PublishSpawn(Func<string, Vector3, Quaternion, Item> spawn)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.items.spawn", spawn);
		}

		public static SortedDictionary<string, object[]> Definitions()
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.items.definitions") is SortedDictionary<string, object[]> result)
			{
				return result;
			}
			SortedDictionary<string, object[]> sortedDictionary = new SortedDictionary<string, object[]>(StringComparer.Ordinal);
			AppDomain.CurrentDomain.SetData("lycans.mods.items.definitions", sortedDictionary);
			return sortedDictionary;
		}
	}
	public static class DevMode
	{
		private const string LoadedDevKey = "lycans.mods.devmode.loaded";

		private const string SkippedKey = "lycans.mods.devmode.skipped";

		private static bool? _enabled;

		public static bool Enabled
		{
			get
			{
				if (_enabled.HasValue)
				{
					return _enabled.Value;
				}
				_enabled = false;
				try
				{
					string path = Path.Combine(Paths.ConfigPath, "lycans.core.cfg");
					if (File.Exists(path))
					{
						string[] array = File.ReadAllLines(path);
						for (int i = 0; i < array.Length; i++)
						{
							string[] array2 = array[i].Split(new char[1] { '=' });
							if (array2.Length == 2 && array2[0].Trim() == "ModeDev")
							{
								_enabled = array2[1].Trim().Equals("true", StringComparison.OrdinalIgnoreCase);
							}
						}
					}
				}
				catch (Exception ex)
				{
					Log.Warning("[DevMode] Lecture de lycans.core.cfg impossible : " + ex.Message);
				}
				return _enabled.Value;
			}
		}

		public static IReadOnlyCollection<string> Skipped => List("lycans.mods.devmode.skipped");

		public static bool IsDevOnly(string status)
		{
			if (!(status == "dev"))
			{
				return status == "private";
			}
			return true;
		}

		public static bool Guard(BaseUnityPlugin plugin, string modName, string status)
		{
			KeepAlive(plugin);
			if (!IsDevOnly(status))
			{
				return true;
			}
			if (!Enabled)
			{
				List("lycans.mods.devmode.skipped").Add(modName);
				((Behaviour)plugin).enabled = false;
				Log.Info("[DevMode] « " + modName + " » (" + status + ") non chargé : mode DEV désactivé (ModeDev dans lycans.core.cfg).");
				return false;
			}
			List("lycans.mods.devmode.loaded").Add(modName);
			return true;
		}

		private static void KeepAlive(BaseUnityPlugin plugin)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			if (!((Object)(object)plugin == (Object)null))
			{
				GameObject gameObject = ((Component)plugin).gameObject;
				if ((int)((Object)gameObject).hideFlags != 61)
				{
					((Object)gameObject).hideFlags = (HideFlags)61;
					Object.DontDestroyOnLoad((Object)(object)gameObject);
				}
			}
		}

		public static bool IsLoadedDevMod(string modName)
		{
			return List("lycans.mods.devmode.loaded").Contains(modName);
		}

		private static HashSet<string> List(string key)
		{
			if (AppDomain.CurrentDomain.GetData(key) is HashSet<string> result)
			{
				return result;
			}
			HashSet<string> hashSet = new HashSet<string>();
			AppDomain.CurrentDomain.SetData(key, hashSet);
			return hashSet;
		}
	}
	public static class Disease
	{
		private const string EnabledKey = "lycans.mods.disease.enabled";

		private const string InfectKey = "lycans.mods.disease.infect";

		private const string CureKey = "lycans.mods.disease.cure";

		private const string StageKey = "lycans.mods.disease.stage";

		public static bool IsEnabled
		{
			get
			{
				if (AppDomain.CurrentDomain.GetData("lycans.mods.disease.enabled") is Func<bool> func)
				{
					return func();
				}
				return false;
			}
		}

		public static void PublishImplementation(Func<bool> enabled, Action<PlayerController> infect, Action<PlayerController> cure, Func<PlayerController, int> stage)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.disease.enabled", enabled);
			AppDomain.CurrentDomain.SetData("lycans.mods.disease.infect", infect);
			AppDomain.CurrentDomain.SetData("lycans.mods.disease.cure", cure);
			AppDomain.CurrentDomain.SetData("lycans.mods.disease.stage", stage);
		}

		public static void Infect(PlayerController player)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.disease.infect") is Action<PlayerController> action)
			{
				action(player);
			}
		}

		public static void Cure(PlayerController player)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.disease.cure") is Action<PlayerController> action)
			{
				action(player);
			}
		}

		public static int Stage(PlayerController player)
		{
			if (!(AppDomain.CurrentDomain.GetData("lycans.mods.disease.stage") is Func<PlayerController, int> func))
			{
				return 0;
			}
			return func(player);
		}
	}
	public enum ExtendedRole
	{
		Villager,
		Alchemist,
		Hunter,
		Wolf,
		Porcupines,
		Knight,
		Alpha,
		Snake,
		LittleGirl,
		Rat,
		None,
		Maire,
		BigWolf,
		Chef
	}
	public static class ExtendedRoles
	{
		private const string GetKey = "lycans.mods.roles.get";

		private const string SetKey = "lycans.mods.roles.set";

		private const string SlotCountKey = "lycans.mods.roles.slotcount";

		private const string DisplayKey = "lycans.mods.roles.display";

		public static bool IsAvailable => AppDomain.CurrentDomain.GetData("lycans.mods.roles.get") != null;

		public static int SlotCount
		{
			get
			{
				object data = AppDomain.CurrentDomain.GetData("lycans.mods.roles.slotcount");
				if (data is int)
				{
					return (int)data;
				}
				return 0;
			}
		}

		public static void PublishImplementation(Func<int, ExtendedRole> get, Action<int, ExtendedRole> set, int slotCount)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.roles.get", (Func<int, int>)((int index) => (int)get(index)));
			AppDomain.CurrentDomain.SetData("lycans.mods.roles.set", (Action<int, int>)delegate(int index, int role)
			{
				set(index, (ExtendedRole)role);
			});
			AppDomain.CurrentDomain.SetData("lycans.mods.roles.slotcount", slotCount);
		}

		public static ExtendedRole Get(int playerIndex)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.roles.get") is Func<int, int> func)
			{
				return (ExtendedRole)func(playerIndex);
			}
			return ExtendedRole.None;
		}

		public static ExtendedRole Get(PlayerController player)
		{
			if (!((Object)(object)player != (Object)null))
			{
				return ExtendedRole.None;
			}
			return Get((int)player.Index);
		}

		public static void RegisterDisplay(ExtendedRole role, string translationKey, Color color, bool wolfTeam, Func<bool> showMates = null, Func<string> suffix = null)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Displays()[(int)role] = new object[5] { translationKey, color, wolfTeam, showMates, suffix };
		}

		public static bool TryGetDisplay(ExtendedRole role, out string translationKey, out Color color, out bool wolfTeam, out Func<bool> showMates, out Func<string> suffix)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			if (Displays().TryGetValue((int)role, out var value))
			{
				translationKey = (string)value[0];
				color = (Color)value[1];
				wolfTeam = (bool)value[2];
				showMates = (Func<bool>)value[3];
				suffix = (Func<string>)value[4];
				return true;
			}
			translationKey = null;
			color = Color.white;
			wolfTeam = false;
			showMates = null;
			suffix = null;
			return false;
		}

		public static bool IsWolfTeam(PlayerController player)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if ((int)player.Role == 1)
			{
				return true;
			}
			string translationKey;
			Color color;
			bool wolfTeam;
			Func<bool> showMates;
			Func<string> suffix;
			return TryGetDisplay(Get(player), out translationKey, out color, out wolfTeam, out showMates, out suffix) && wolfTeam;
		}

		private static Dictionary<int, object[]> Displays()
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.roles.display") is Dictionary<int, object[]> result)
			{
				return result;
			}
			Dictionary<int, object[]> dictionary = new Dictionary<int, object[]>();
			AppDomain.CurrentDomain.SetData("lycans.mods.roles.display", dictionary);
			return dictionary;
		}

		public static void Set(int playerIndex, ExtendedRole role)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.roles.set") is Action<int, int> action)
			{
				action(playerIndex, (int)role);
			}
			else
			{
				Log.Warning("[ExtendedRoles] Set ignoré : mod_roles non chargé.");
			}
		}
	}
	public static class GamePhases
	{
		private static NetworkRunner Runner => ((SimulationBehaviour)(GameManager.Instance?)).Runner;

		private static bool InPlay
		{
			get
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Invalid comparison between Unknown and I4
				//IL_0045: 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)
				if ((Object)(object)Runner != (Object)null && Runner.IsServer && (Object)(object)GameManager.State != (Object)null && (int)GameManager.State.Current == 2 && (Object)(object)GameManager.LightingManager != (Object)null && !NetworkBool.op_Implicit(GameManager.LightingManager.IsTransition))
				{
					return !NetworkBool.op_Implicit(GameManager.Instance.IsFinished);
				}
				return false;
			}
		}

		public static bool CanStartNight
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				if (InPlay)
				{
					return !NetworkBool.op_Implicit(GameManager.LightingManager.IsNight);
				}
				return false;
			}
		}

		public static bool CanStartDawn
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				if (InPlay)
				{
					return NetworkBool.op_Implicit(GameManager.LightingManager.IsNight);
				}
				return false;
			}
		}

		public static bool CanEndVote
		{
			get
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Invalid comparison between Unknown and I4
				if ((Object)(object)Runner != (Object)null && Runner.IsServer && (Object)(object)GameManager.State != (Object)null)
				{
					return (int)GameManager.State.Current == 4;
				}
				return false;
			}
		}

		public static void Transition()
		{
			//IL_0018: 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)
			if (InPlay)
			{
				GameManager.Rpc_Transition(Runner);
				GameManager.LightingManager.IsTransition = NetworkBool.op_Implicit(true);
				Log.Info("[GamePhases] Transition forcée (" + (NetworkBool.op_Implicit(GameManager.LightingManager.IsNight) ? "aube" : "tombée de la nuit") + ").");
			}
		}

		public static void StartNight()
		{
			if (CanStartNight)
			{
				Transition();
			}
		}

		public static void EndVote()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (CanEndVote)
			{
				GameManager.Instance.VoteTimer = TickTimer.CreateFromSeconds(Runner, 0.1f);
				Log.Info("[GamePhases] Fin du vote forcée.");
			}
		}
	}
	public sealed class StateEnterContext
	{
		private readonly IDictionary<string, object> _data;

		public EGameState Entered => (EGameState)_data["entered"];

		public EGameState From => (EGameState)_data["from"];

		public bool IsServer => (bool)_data["server"];

		public bool IsPlayer => (bool)_data["player"];

		public bool Cancel
		{
			get
			{
				return HookPipeline.IsCancelled(_data);
			}
			set
			{
				_data["cancel"] = HookPipeline.Box(value);
			}
		}

		internal StateEnterContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class GameStateRules
	{
		public unsafe static string Method(EGameState state)
		{
			return "GameState.Enter." + ((object)(*(EGameState*)(&state))/*cast due to .constrained prefix*/).ToString();
		}

		public static void BeforeEnter(EGameState state, int priority, string owner, Action<StateEnterContext> step)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			HookPipeline.Register(Method(state), priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				step(new StateEnterContext(data));
			});
		}

		public static void AfterEnter(EGameState state, int priority, string owner, Action<StateEnterContext> step)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			HookPipeline.Register(Method(state), priority, owner, HookPhase.After, delegate(IDictionary<string, object> data)
			{
				step(new StateEnterContext(data));
			});
		}

		public static void OnRoundStartServer(int priority, string owner, Action step)
		{
			AfterEnter((EGameState)2, priority, owner, delegate(StateEnterContext ctx)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Invalid comparison between Unknown and I4
				if (ctx.IsServer && (int)ctx.From == 1)
				{
					step();
				}
			});
		}

		public static IDictionary<string, object> NewData(EGameState entered, EGameState from, bool isServer, bool isPlayer)
		{
			//IL_000b: 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)
			return new Dictionary<string, object>
			{
				["entered"] = entered,
				["from"] = from,
				["server"] = HookPipeline.Box(isServer),
				["player"] = HookPipeline.Box(isPlayer),
				["cancel"] = HookPipeline.False
			};
		}
	}
	public enum HookPhase
	{
		Before,
		After
	}
	public static class HookPipeline
	{
		public const string CancelKey = "cancel";

		public static readonly object True = true;

		public static readonly object False = false;

		private const string StepsKey = "lycans.mods.hooks.steps";

		private const string ConflictsKey = "lycans.mods.hooks.conflicts";

		private const string CacheKey = "lycans.mods.hooks.cache";

		private static readonly object Lock = new object();

		public static IReadOnlyList<string> ConflictMessages
		{
			get
			{
				lock (Lock)
				{
					return Conflicts().ToArray();
				}
			}
		}

		public static void Register(string method, int priority, string owner, HookPhase phase, Action<IDictionary<string, object>> step)
		{
			lock (Lock)
			{
				Dictionary<string, List<Tuple<int, string, int, Action<IDictionary<string, object>>>>> dictionary = Steps();
				if (!dictionary.TryGetValue(method, out var value))
				{
					value = (dictionary[method] = new List<Tuple<int, string, int, Action<IDictionary<string, object>>>>());
				}
				value.RemoveAll((Tuple<int, string, int, Action<IDictionary<string, object>>> s) => s.Item1 == priority && s.Item2 == owner);
				Tuple<int, string, int, Action<IDictionary<string, object>>> tuple = value.Find((Tuple<int, string, int, Action<IDictionary<string, object>>> s) => s.Item1 == priority);
				if (tuple != null)
				{
					string text = method + " : priorité " + priority + " demandée par « " + owner + " » mais déjà prise par « " + tuple.Item2 + " ». Les deux étapes sont désactivées — change la priorité de l'un des deux mods.";
					Conflicts().Add(text);
					Log.Error("[HookPipeline] " + text);
				}
				value.Add(Tuple.Create(priority, owner, (int)phase, step));
				value.Sort((Tuple<int, string, int, Action<IDictionary<string, object>>> a, Tuple<int, string, int, Action<IDictionary<string, object>>> b) => a.Item1.CompareTo(b.Item1));
				Cache().Clear();
			}
		}

		public static bool RunBefore(string method, IDictionary<string, object> data)
		{
			Tuple<int, string, int, Action<IDictionary<string, object>>>[] array = Active(method, HookPhase.Before);
			foreach (Tuple<int, string, int, Action<IDictionary<string, object>>> tuple in array)
			{
				try
				{
					tuple.Item4(data);
				}
				catch (Exception ex)
				{
					Log.Error("[HookPipeline] " + method + " / « " + tuple.Item2 + " » (priorité " + tuple.Item1 + ") en erreur : " + ex);
				}
				if (IsCancelled(data))
				{
					return true;
				}
			}
			return false;
		}

		public static void RunAfter(string method, IDictionary<string, object> data)
		{
			Tuple<int, string, int, Action<IDictionary<string, object>>>[] array = Active(method, HookPhase.After);
			foreach (Tuple<int, string, int, Action<IDictionary<string, object>>> tuple in array)
			{
				try
				{
					tuple.Item4(data);
				}
				catch (Exception ex)
				{
					Log.Error("[HookPipeline] " + method + " / « " + tuple.Item2 + " » (priorité " + tuple.Item1 + ") en erreur : " + ex);
				}
			}
		}

		public static bool IsCancelled(IDictionary<string, object> data)
		{
			bool flag = default(bool);
			int num;
			if (data.TryGetValue("cancel", out var value))
			{
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		public static object Box(bool value)
		{
			if (!value)
			{
				return False;
			}
			return True;
		}

		public static IReadOnlyList<string> Describe(string method)
		{
			lock (Lock)
			{
				List<string> list = new List<string>();
				if (Steps().TryGetValue(method, out var value))
				{
					foreach (Tuple<int, string, int, Action<IDictionary<string, object>>> item in value)
					{
						list.Add(item.Item1 + " · " + item.Item2 + " · " + ((HookPhase)item.Item3/*cast due to .constrained prefix*/).ToString() + (IsDuplicate(value, item.Item1) ? " · CONFLIT (désactivée)" : ""));
					}
				}
				return list;
			}
		}

		private static Tuple<int, string, int, Action<IDictionary<string, object>>>[] Active(string method, HookPhase phase)
		{
			lock (Lock)
			{
				Dictionary<string, Tuple<int, string, int, Action<IDictionary<string, object>>>[][]> dictionary = Cache();
				if (!dictionary.TryGetValue(method, out var value))
				{
					value = (dictionary[method] = new Tuple<int, string, int, Action<IDictionary<string, object>>>[2][]);
				}
				if (value[(int)phase] != null)
				{
					return value[(int)phase];
				}
				List<Tuple<int, string, int, Action<IDictionary<string, object>>>> list = new List<Tuple<int, string, int, Action<IDictionary<string, object>>>>();
				if (Steps().TryGetValue(method, out var value2))
				{
					foreach (Tuple<int, string, int, Action<IDictionary<string, object>>> item in value2)
					{
						if (item.Item3 == (int)phase && !IsDuplicate(value2, item.Item1))
						{
							list.Add(item);
						}
					}
				}
				value[(int)phase] = list.ToArray();
				return value[(int)phase];
			}
		}

		private static bool IsDuplicate(List<Tuple<int, string, int, Action<IDictionary<string, object>>>> list, int priority)
		{
			return list.FindAll((Tuple<int, string, int, Action<IDictionary<string, object>>> s) => s.Item1 == priority).Count > 1;
		}

		private static Dictionary<string, List<Tuple<int, string, int, Action<IDictionary<string, object>>>>> Steps()
		{
			return GetOrCreate<Dictionary<string, List<Tuple<int, string, int, Action<IDictionary<string, object>>>>>>("lycans.mods.hooks.steps");
		}

		private static List<string> Conflicts()
		{
			return GetOrCreate<List<string>>("lycans.mods.hooks.conflicts");
		}

		private static Dictionary<string, Tuple<int, string, int, Action<IDictionary<string, object>>>[][]> Cache()
		{
			return GetOrCreate<Dictionary<string, Tuple<int, string, int, Action<IDictionary<string, object>>>[][]>>("lycans.mods.hooks.cache");
		}

		private static T GetOrCreate<T>(string key) where T : class, new()
		{
			if (AppDomain.CurrentDomain.GetData(key) is T result)
			{
				return result;
			}
			T val = new T();
			AppDomain.CurrentDomain.SetData(key, val);
			return val;
		}
	}
	public sealed class InteractRayContext
	{
		private readonly IDictionary<string, object> _data;

		public PlayerController Player => (PlayerController)_data["player"];

		public float Distance
		{
			get
			{
				return ((float[])_data["values"])[0];
			}
			set
			{
				((float[])_data["values"])[0] = value;
			}
		}

		public bool IsMeeting => (int)GameManager.LocalGameState == 4;

		internal InteractRayContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class InteractRayRules
	{
		public const string Method = "PlayerInteract.Update";

		public static void AdjustDistance(int priority, string owner, Action<InteractRayContext> step)
		{
			HookPipeline.Register("PlayerInteract.Update", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				step(new InteractRayContext(data));
			});
		}

		public static IDictionary<string, object> NewData()
		{
			return new Dictionary<string, object> { ["values"] = new float[1] };
		}

		public static void Reset(IDictionary<string, object> data, PlayerController player, float distance)
		{
			data["player"] = player;
			data["cancel"] = HookPipeline.False;
			((float[])data["values"])[0] = distance;
		}
	}
	public sealed class InteractContext
	{
		private readonly IDictionary<string, object> _data;

		public PlayerController Player => (PlayerController)_data["player"];

		public bool IsPrimary => (bool)_data["primary"];

		public GameObject Target => (GameObject)_data["target"];

		public PlayerController TargetPlayer
		{
			get
			{
				if (!((Object)(object)Target != (Object)null))
				{
					return null;
				}
				return Target.GetComponentInParent<PlayerController>();
			}
		}

		public bool Handled
		{
			get
			{
				return HookPipeline.IsCancelled(_data);
			}
			set
			{
				_data["cancel"] = HookPipeline.Box(value);
			}
		}

		internal InteractContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class InteractRules
	{
		public const string Method = "PlayerController.Interact";

		public static void Before(int priority, string owner, Action<InteractContext> step)
		{
			HookPipeline.Register("PlayerController.Interact", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				step(new InteractContext(data));
			});
		}

		public static void After(int priority, string owner, Action<InteractContext> step)
		{
			HookPipeline.Register("PlayerController.Interact", priority, owner, HookPhase.After, delegate(IDictionary<string, object> data)
			{
				step(new InteractContext(data));
			});
		}

		public static IDictionary<string, object> NewData(PlayerController player, bool isPrimary)
		{
			return new Dictionary<string, object>
			{
				["player"] = player,
				["primary"] = HookPipeline.Box(isPrimary),
				["target"] = player._targetObject,
				["cancel"] = HookPipeline.False
			};
		}
	}
	public sealed class ItemSpawnContext
	{
		private readonly IDictionary<string, object> _data;

		public GameManager Game => (GameManager)_data["game"];

		public List<Item> Prefabs => (List<Item>)_data["prefabs"];

		public Dictionary<string, Action<Vector3, Quaternion>> CustomItems => (Dictionary<string, Action<Vector3, Quaternion>>)_data["custom"];

		public bool BulletsAllowed
		{
			get
			{
				return (bool)_data["bullets"];
			}
			set
			{
				_data["bullets"] = HookPipeline.Box(value);
			}
		}

		internal ItemSpawnContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class ItemSpawnRules
	{
		public const string Method = "GameManager.SpawnRandomItems";

		public static void Before(int priority, string owner, Action<ItemSpawnContext> step)
		{
			HookPipeline.Register("GameManager.SpawnRandomItems", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				step(new ItemSpawnContext(data));
			});
		}

		public static IDictionary<string, object> NewData(GameManager game)
		{
			return new Dictionary<string, object>
			{
				["game"] = game,
				["prefabs"] = new List<Item>(game.spawnableItemPrefabs),
				["custom"] = new Dictionary<string, Action<Vector3, Quaternion>>(),
				["bullets"] = HookPipeline.True,
				["cancel"] = HookPipeline.False
			};
		}
	}
	public sealed class LightingContext
	{
		private readonly IDictionary<string, object> _data;

		public LightingManager Manager => (LightingManager)_data["manager"];

		public float TimeOfDay => Manager._localTimeOfDay;

		public bool IsNightTime
		{
			get
			{
				if (!(TimeOfDay >= 18f))
				{
					return TimeOfDay < 6f;
				}
				return true;
			}
		}

		public bool IsServer
		{
			get
			{
				if ((Object)(object)((SimulationBehaviour)Manager).Runner != (Object)null)
				{
					return ((SimulationBehaviour)Manager).Runner.IsServer;
				}
				return false;
			}
		}

		public bool FlatAmbient
		{
			get
			{
				return (bool)_data["flat"];
			}
			set
			{
				_data["flat"] = HookPipeline.Box(value);
			}
		}

		internal LightingContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class LightingRules
	{
		public const string UpdateMethod = "LightingManager.UpdateLighting";

		public const string NightMethod = "LightingManager.NightChanged";

		public const string AmbientMethod = "LightingManager.FlatAmbient";

		public static void OnUpdate(int priority, string owner, Action<LightingContext> step)
		{
			HookPipeline.Register("LightingManager.UpdateLighting", priority, owner, HookPhase.After, delegate(IDictionary<string, object> data)
			{
				step(new LightingContext(data));
			});
		}

		public static void OnNightChanged(int priority, string owner, Action<LightingContext> step)
		{
			HookPipeline.Register("LightingManager.NightChanged", priority, owner, HookPhase.After, delegate(IDictionary<string, object> data)
			{
				step(new LightingContext(data));
			});
		}

		public static void ForceFlatAmbient(int priority, string owner, Func<LightingContext, bool> wantsFlat)
		{
			HookPipeline.Register("LightingManager.FlatAmbient", priority, owner, HookPhase.After, delegate(IDictionary<string, object> data)
			{
				LightingContext lightingContext = new LightingContext(data);
				if (!lightingContext.FlatAmbient && wantsFlat(lightingContext))
				{
					lightingContext.FlatAmbient = true;
				}
			});
		}

		public static IDictionary<string, object> NewData()
		{
			return new Dictionary<string, object>();
		}

		public static void Reset(IDictionary<string, object> data, LightingManager manager)
		{
			data["manager"] = manager;
			data["flat"] = HookPipeline.False;
			data["cancel"] = HookPipeline.False;
		}
	}
	public static class Log
	{
		private static ManualLogSource _source;

		private static readonly Dictionary<string, float> _lastThrottled = new Dictionary<string, float>();

		public static void Use(ManualLogSource source)
		{
			_source = source;
		}

		public static void Info(string message)
		{
			if (_source != null)
			{
				_source.LogInfo((object)message);
			}
			else
			{
				Console.WriteLine("[Info] " + message);
			}
		}

		public static void Warning(string message)
		{
			if (_source != null)
			{
				_source.LogWarning((object)message);
			}
			else
			{
				Console.WriteLine("[Warning] " + message);
			}
		}

		public static void Error(string message)
		{
			if (_source != null)
			{
				_source.LogError((object)message);
			}
			else
			{
				Console.WriteLine("[Error] " + message);
			}
		}

		public static void Throttled(string key, float intervalSeconds, string message)
		{
			float unscaledTime = Time.unscaledTime;
			if (!_lastThrottled.TryGetValue(key, out var value) || !(unscaledTime - value < intervalSeconds))
			{
				_lastThrottled[key] = unscaledTime;
				Info(message);
			}
		}
	}
	public sealed class LootCollectContext
	{
		private readonly IDictionary<string, object> _data;

		public PlayerController Player => (PlayerController)_data["player"];

		public Loot Loot => (Loot)_data["loot"];

		public int Score
		{
			get
			{
				return (int)_data["score"];
			}
			set
			{
				_data["score"] = value;
			}
		}

		public int Hunger
		{
			get
			{
				return (int)_data["hunger"];
			}
			set
			{
				_data["hunger"] = value;
			}
		}

		public bool Cancel
		{
			get
			{
				return HookPipeline.IsCancelled(_data);
			}
			set
			{
				_data["cancel"] = HookPipeline.Box(value);
			}
		}

		internal LootCollectContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class LootRules
	{
		public const string Method = "Loot.Rpc_Collect";

		public static void Before(int priority, string owner, Action<LootCollectContext> step)
		{
			HookPipeline.Register("Loot.Rpc_Collect", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				step(new LootCollectContext(data));
			});
		}

		public static void After(int priority, string owner, Action<LootCollectContext> step)
		{
			HookPipeline.Register("Loot.Rpc_Collect", priority, owner, HookPhase.After, delegate(IDictionary<string, object> data)
			{
				step(new LootCollectContext(data));
			});
		}

		public static IDictionary<string, object> NewData(PlayerController player, Loot loot)
		{
			return new Dictionary<string, object>
			{
				["player"] = player,
				["loot"] = loot,
				["score"] = loot.ScoreValue,
				["hunger"] = loot.HungerValue,
				["cancel"] = HookPipeline.False
			};
		}
	}
	public static class ModAssets
	{
		private static readonly Dictionary<string, AssetBundle> Bundles = new Dictionary<string, AssetBundle>();

		private static readonly Dictionary<string, Sprite> Icons = new Dictionary<string, Sprite>();

		public static AssetBundle Bundle(Assembly assembly, string fileName)
		{
			if (Bundles.TryGetValue(fileName, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			byte[] array = Read(assembly, "LycansBundle." + fileName);
			if (array == null)
			{
				return null;
			}
			AssetBundle val = AssetBundle.LoadFromMemory(array);
			if ((Object)(object)val == (Object)null)
			{
				foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
				{
					if ((Object)(object)allLoadedAssetBundle != (Object)null && string.Equals(((Object)allLoadedAssetBundle).name, Path.GetFileNameWithoutExtension(fileName), StringComparison.OrdinalIgnoreCase))
					{
						val = allLoadedAssetBundle;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Log.Warning("[ModAssets] Bundle illisible : " + fileName);
			}
			Bundles[fileName] = val;
			return val;
		}

		public static GameObject FirstPrefab(Assembly assembly, string fileName)
		{
			AssetBundle val = Bundle(assembly, fileName);
			GameObject[] array = (((Object)(object)val != (Object)null) ? val.LoadAllAssets<GameObject>() : null);
			if (array == null || array.Length == 0)
			{
				return null;
			}
			return array[0];
		}

		public static T FirstAsset<T>(Assembly assembly, string fileName) where T : Object
		{
			AssetBundle val = Bundle(assembly, fileName);
			T[] array = (((Object)(object)val != (Object)null) ? val.LoadAllAssets<T>() : null);
			if (array == null || array.Length == 0)
			{
				Log.Warning("[ModAssets] Aucun " + typeof(T).Name + " dans " + fileName);
				return default(T);
			}
			return array[0];
		}

		public static Sprite Icon(Assembly assembly, string fileName)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (Icons.TryGetValue(fileName, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			byte[] array = Read(assembly, "LycansIcon." + fileName);
			if (array == null)
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				Log.Warning("[ModAssets] Icône illisible : " + fileName);
				return null;
			}
			Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			Icons[fileName] = val2;
			return val2;
		}

		private static byte[] Read(Assembly assembly, string resource)
		{
			using Stream stream = assembly.GetManifestResourceStream(resource);
			if (stream == null)
			{
				Log.Warning("[ModAssets] Ressource absente de la DLL : " + resource);
				return null;
			}
			MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}
	}
	public static class ModConfigPanel
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static hook_Spawned <>9__7_0;

			internal void <EnsureInstalled>b__7_0(orig_Spawned orig, GameManager self)
			{
				orig.Invoke(self);
				CreateCarrierIfNeeded();
			}
		}

		private const string HookInstalledKey = "lycans.mods.config.panelhookinstalled";

		private const string ReplacedKey = "lycans.mods.config.panelreplaced";

		private static readonly object Lock = new object();

		private static GameObject _carrier;

		public static bool Replaced
		{
			get
			{
				object data = AppDomain.CurrentDomain.GetData("lycans.mods.config.panelreplaced");
				bool flag = default(bool);
				int num;
				if (data is bool)
				{
					flag = (bool)data;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			set
			{
				AppDomain.CurrentDomain.SetData("lycans.mods.config.panelreplaced", value);
			}
		}

		public static void EnsureInstalled()
		{
			//IL_0062: 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_006d: Expected O, but got Unknown
			lock (Lock)
			{
				object data = AppDomain.CurrentDomain.GetData("lycans.mods.config.panelhookinstalled");
				bool flag = default(bool);
				int num;
				if (data is bool)
				{
					flag = (bool)data;
					num = 1;
				}
				else
				{
					num = 0;
				}
				if (((uint)num & (flag ? 1u : 0u)) != 0)
				{
					return;
				}
				AppDomain.CurrentDomain.SetData("lycans.mods.config.panelhookinstalled", true);
				object obj = <>c.<>9__7_0;
				if (obj == null)
				{
					hook_Spawned val = delegate(orig_Spawned orig, GameManager self)
					{
						orig.Invoke(self);
						CreateCarrierIfNeeded();
					};
					<>c.<>9__7_0 = val;
					obj = (object)val;
				}
				GameManager.Spawned += (hook_Spawned)obj;
				Log.Info("[ModConfigPanel] Hook GameManager.Spawned installé, carrier créé au premier démarrage de partie.");
			}
		}

		private static void CreateCarrierIfNeeded()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)_carrier != (Object)null))
			{
				_carrier = new GameObject("LycansModConfigPanel");
				Object.DontDestroyOnLoad((Object)(object)_carrier);
				_carrier.AddComponent<ModConfigPanelBehaviour>();
				Log.Info("[ModConfigPanel] Carrier créé (" + ((Object)_carrier).name + ").");
			}
		}
	}
	internal sealed class ModConfigPanelBehaviour : MonoBehaviour
	{
		private const KeyCode ToggleKey = (KeyCode)290;

		private const string CouncilTabId = "\0council";

		private bool _open;

		private bool _loggedFirstOnGui;

		private Rect _rect = new Rect(20f, 20f, 560f, 440f);

		private Vector2 _tabScroll;

		private Vector2 _contentScroll;

		private string _search = "";

		private string _selectedMod;

		private static GUIStyle _richLabel;

		private static GUIStyle RichLabel
		{
			get
			{
				//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_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_002c: Expected O, but got Unknown
				object obj = _richLabel;
				if (obj == null)
				{
					GUIStyle val = new GUIStyle(GUI.skin.label)
					{
						richText = true,
						wordWrap = true
					};
					_richLabel = val;
					obj = (object)val;
				}
				return (GUIStyle)obj;
			}
		}

		private void Awake()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Log.Info("[ModConfigPanel] Awake : composant créé, en attente de " + ((object)(KeyCode)290/*cast due to .constrained prefix*/).ToString() + ".");
		}

		private void OnEnable()
		{
			Log.Info("[ModConfigPanel] OnEnable.");
		}

		private void OnDisable()
		{
			Log.Info("[ModConfigPanel] OnDisable (le composant vient d'être désactivé !).");
		}

		private void OnDestroy()
		{
			Log.Info("[ModConfigPanel] OnDestroy (le composant vient d'être détruit !).");
			if (_open)
			{
				CursorControl.Release();
			}
		}

		private void Update()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			string reason;
			bool flag = CanConfigure(out reason);
			Log.Throttled("modconfigpanel.state", 3f, "[ModConfigPanel] CanConfigure=" + flag + " (" + reason + ")");
			if (ModConfigPanel.Replaced)
			{
				SetOpen(value: false);
				return;
			}
			if (Input.GetKeyDown((KeyCode)290))
			{
				Log.Info("[ModConfigPanel] " + ((object)(KeyCode)290/*cast due to .constrained prefix*/).ToString() + " détecté (appui). CanConfigure=" + flag + " (" + reason + ")");
				if (flag)
				{
					SetOpen(!_open);
				}
				else
				{
					Log.Info("[ModConfigPanel] Touche ignorée : condition non remplie (" + reason + ").");
				}
			}
			if (!flag)
			{
				SetOpen(value: false);
			}
		}

		private void SetOpen(bool value)
		{
			if (_open != value)
			{
				_open = value;
				if (value)
				{
					CursorControl.Request();
				}
				else
				{
					CursorControl.Release();
				}
			}
		}

		private static bool CanConfigure(out string reason)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			GameManager instance = GameManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				reason = "GameManager.Instance == null (pas en partie ?)";
				return false;
			}
			if ((Object)(object)((SimulationBehaviour)instance).Runner == (Object)null)
			{
				reason = "Runner == null";
				return false;
			}
			if (!((SimulationBehaviour)instance).Runner.IsRunning)
			{
				reason = "Runner.IsRunning == false";
				return false;
			}
			if ((int)GameManager.LocalGameState != 1)
			{
				reason = "état de partie = " + ((object)Unsafe.As<EGameState, EGameState>(ref GameManager.LocalGameState)/*cast due to .constrained prefix*/).ToString() + " (attendu Pregame)";
				return false;
			}
			reason = "ok";
			return true;
		}

		private static bool IsHost()
		{
			GameManager instance = GameManager.Instance;
			if (instance == null)
			{
				return false;
			}
			NetworkRunner runner = ((SimulationBehaviour)instance).Runner;
			return ((runner != null) ? new bool?(runner.IsServer) : ((bool?)null)) == true;
		}

		private void OnGUI()
		{
			//IL_003d: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedFirstOnGui)
			{
				_loggedFirstOnGui = true;
				Log.Info("[ModConfigPanel] OnGUI appelé pour la première fois (Unity invoque bien ce composant).");
			}
			if (_open)
			{
				string text = (IsHost() ? "hôte" : "joueur — tes changements deviennent des propositions");
				_rect = GUILayout.Window(113755157, _rect, new WindowFunction(DrawWindow), "Configuration des mods · " + text + " (" + ((object)(KeyCode)290/*cast due to .constrained prefix*/).ToString() + " pour fermer)", Array.Empty<GUILayoutOption>());
			}
		}

		private void DrawWindow(int id)
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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_001a: 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_01bc: 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_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			IReadOnlyList<ModConfigSection> sections = ModConfigRegistry.Sections;
			IReadOnlyList<string> conflictMessages = HookPipeline.ConflictMessages;
			if (conflictMessages.Count > 0)
			{
				Color color = GUI.color;
				GUI.color = new Color(1f, 0.35f, 0.35f);
				foreach (string item in conflictMessages)
				{
					GUILayout.Label("ERREUR — " + item, Array.Empty<GUILayoutOption>());
				}
				GUI.color = color;
				GUILayout.Space(6f);
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) });
			GUILayout.Label("Recherche", Array.Empty<GUILayoutOption>());
			_search = GUILayout.TextField(_search, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) });
			GUILayout.Space(6f);
			_tabScroll = GUILayout.BeginScrollView(_tabScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(170f),
				GUILayout.Height(330f)
			});
			string text = _search.Trim().ToLowerInvariant();
			foreach (ModConfigSection item2 in sections)
			{
				if (text.Length <= 0 || item2.ModName.ToLowerInvariant().IndexOf(text, StringComparison.Ordinal) >= 0)
				{
					DrawTabButton(item2.ModName, item2.ModName);
				}
			}
			GUILayout.EndScrollView();
			GUILayout.Space(6f);
			DrawTabButton("\0council", "Conseil");
			GUILayout.EndVertical();
			GUILayout.Space(10f);
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			_contentScroll = GUILayout.BeginScrollView(_contentScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(380f) });
			DrawSelectedContent(sections);
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
		}

		private void DrawTabButton(string id, string label)
		{
			bool flag = _selectedMod == id;
			if (GUILayout.Toggle(flag, label, GUIStyle.op_Implicit("Button"), Array.Empty<GUILayoutOption>()))
			{
				_selectedMod = id;
			}
			else if (flag)
			{
				_selectedMod = null;
			}
		}

		private void DrawSelectedContent(IReadOnlyList<ModConfigSection> sections)
		{
			if (_selectedMod == null)
			{
				GUILayout.Label("Choisis un mod à gauche (ou cherche son nom).", Array.Empty<GUILayoutOption>());
				return;
			}
			if (_selectedMod == "\0council")
			{
				DrawCouncil();
				return;
			}
			ModConfigSection modConfigSection = null;
			foreach (ModConfigSection section in sections)
			{
				if (section.ModName == _selectedMod)
				{
					modConfigSection = section;
					break;
				}
			}
			if (modConfigSection == null)
			{
				GUILayout.Label("Ce mod n'est plus chargé.", Array.Empty<GUILayoutOption>());
				return;
			}
			bool flag = modConfigSection.GetEnabled();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			bool flag2 = GUILayout.Toggle(flag, "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(20f) });
			GUILayout.Label("<b>" + modConfigSection.ModName + "</b>", RichLabel, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			if (flag2 != flag)
			{
				modConfigSection.SetEnabled?.Invoke(flag2);
			}
			if (!flag2)
			{
				GUILayout.Label("Mod désactivé.", Array.Empty<GUILayoutOption>());
				return;
			}
			if (!IsHost())
			{
				GUILayout.Label("Tu n'es pas l'hôte : tes changements ci-dessous deviennent des propositions envoyées au Conseil (onglet à gauche).", RichLabel, Array.Empty<GUILayoutOption>());
				GUILayout.Space(6f);
			}
			GUILayout.Space(8f);
			foreach (ModConfigField field in modConfigSection.Fields)
			{
				DrawField(modConfigSection.ModName, field);
			}
		}

		private static void DrawField(string modName, ModConfigField field)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Space(20f);
			GUILayout.Label(field.Label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			object obj = field.Get();
			float oldValueRaw = ToRaw(field.Type, obj);
			object obj2 = obj;
			switch (field.Type)
			{
			case ModConfigFieldType.Bool:
				obj2 = GUILayout.Toggle((bool)obj, "", Array.Empty<GUILayoutOption>());
				break;
			case ModConfigFieldType.Int:
			{
				float num3 = GUILayout.HorizontalSlider((float)(int)obj, field.Min, field.Max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
				GUILayout.Label(((int)num3).ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(32f) });
				obj2 = (int)num3;
				break;
			}
			case ModConfigFieldType.Float:
			{
				float num2 = GUILayout.HorizontalSlider((float)obj, field.Min, field.Max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
				GUILayout.Label(num2.ToString("0.0"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
				obj2 = num2;
				break;
			}
			case ModConfigFieldType.Choice:
			{
				string[] options = field.Options;
				int num = ((options == null) ? 1 : options.Length);
				if (GUILayout.Button(field.Format((int)obj), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) }))
				{
					obj2 = ((int)obj + 1) % num;
				}
				break;
			}
			}
			GUILayout.EndHorizontal();
			if (!object.Equals(obj2, obj))
			{
				if (IsHost())
				{
					field.Set(obj2);
					return;
				}
				float newValueRaw = ToRaw(field.Type, obj2);
				ModProposals.Submit(modName, field.Label, oldValueRaw, newValueRaw);
				Log.Info("[ModConfigPanel] Proposition envoyée : " + modName + " / " + field.Label);
			}
		}

		private static float ToRaw(ModConfigFieldType type, object value)
		{
			return type switch
			{
				ModConfigFieldType.Bool => ((bool)value) ? 1f : 0f, 
				ModConfigFieldType.Int => (int)value, 
				ModConfigFieldType.Choice => (int)value, 
				ModConfigFieldType.Float => (float)value, 
				_ => 0f, 
			};
		}

		private void DrawCouncil()
		{
			//IL_006e: 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)
			GUILayout.Label("<b>Conseil</b>", RichLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			if (!ModProposals.IsAvailable)
			{
				GUILayout.Label("Indisponible : le mod « Lycans Council » n'est pas chargé.", Array.Empty<GUILayoutOption>());
				return;
			}
			IReadOnlyList<ProposalSlot> readOnlyList = ModProposals.List();
			if (readOnlyList.Count == 0)
			{
				GUILayout.Label("Aucune proposition en cours.", Array.Empty<GUILayoutOption>());
				return;
			}
			bool isHost = IsHost();
			int num;
			if (!((Object)(object)PlayerController.Local != (Object)null))
			{
				num = -1;
			}
			else
			{
				PlayerRef val = PlayerController.Local.Ref;
				num = ((PlayerRef)(ref val)).PlayerId;
			}
			int localPlayerId = num;
			foreach (ProposalSlot item in readOnlyList)
			{
				DrawProposal(item, isHost, localPlayerId);
			}
		}

		private static void DrawProposal(ProposalSlot slot, bool isHost, int localPlayerId)
		{
			GUILayout.BeginVertical(GUIStyle.op_Implicit("Box"), Array.Empty<GUILayoutOption>());
			GUILayout.Label("<b>" + slot.ModName + " / " + slot.FieldLabel + "</b>  —  " + DescribeStatus(slot.Status), RichLabel, Array.Empty<GUILayoutOption>());
			string[] obj = new string[6] { "Proposé par le joueur #", null, null, null, null, null };
			int authorPlayerId = slot.AuthorPlayerId;
			obj[1] = authorPlayerId.ToString();
			obj[2] = " : ";
			float oldValueRaw = slot.OldValueRaw;
			obj[3] = oldValueRaw.ToString("0.##");
			obj[4] = " → ";
			oldValueRaw = slot.NewValueRaw;
			obj[5] = oldValueRaw.ToString("0.##");
			GUILayout.Label(string.Concat(obj), Array.Empty<GUILayoutOption>());
			switch (slot.Status)
			{
			case ProposalStatus.PendingHost:
				if (isHost)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					if (GUILayout.Button("Ouvrir le vote", Array.Empty<GUILayoutOption>()))
					{
						ModProposals.HostDecide(slot.Index, approve: true);
					}
					if (GUILayout.Button("Rejeter", Array.Empty<GUILayoutOption>()))
					{
						ModProposals.HostDecide(slot.Index, approve: false);
					}
					GUILayout.EndHorizontal();
				}
				else
				{
					GUILayout.Label("En attente de l'hôte.", Array.Empty<GUILayoutOption>());
				}
				break;
			case ProposalStatus.Voting:
			{
				string[] obj2 = new string[5] { "Votes : ", null, null, null, null };
				authorPlayerId = slot.VotesFor;
				obj2[1] = authorPlayerId.ToString();
				obj2[2] = " pour / ";
				authorPlayerId = slot.VotesAgainst;
				obj2[3] = authorPlayerId.ToString();
				obj2[4] = " contre";
				GUILayout.Label(string.Concat(obj2), Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (localPlayerId >= 0)
				{
					if (GUILayout.Button("Voter pour", Array.Empty<GUILayoutOption>()))
					{
						ModProposals.Vote(slot.Index, voteFor: true);
					}
					if (GUILayout.Button("Voter contre", Array.Empty<GUILayoutOption>()))
					{
						ModProposals.Vote(slot.Index, voteFor: false);
					}
				}
				if (isHost && GUILayout.Button("Clôturer le vote", Array.Empty<GUILayoutOption>()))
				{
					ModProposals.HostCloseVote(slot.Index);
				}
				GUILayout.EndHorizontal();
				break;
			}
			case ProposalStatus.Accepted:
				GUILayout.Label("Acceptée — en cours d'application.", Array.Empty<GUILayoutOption>());
				break;
			case ProposalStatus.Rejected:
				GUILayout.Label("Rejetée.", Array.Empty<GUILayoutOption>());
				break;
			}
			GUILayout.EndVertical();
			GUILayout.Space(6f);
		}

		private static string DescribeStatus(ProposalStatus status)
		{
			return status switch
			{
				ProposalStatus.PendingHost => "en attente de l'hôte", 
				ProposalStatus.Voting => "au vote", 
				ProposalStatus.Accepted => "acceptée", 
				ProposalStatus.Rejected => "rejetée", 
				_ => status.ToString(), 
			};
		}
	}
	public enum ModConfigFieldType
	{
		Bool,
		Int,
		Float,
		Choice
	}
	public static class ModChapters
	{
		public const string Roles = "roles";

		public const string Potions = "potions";

		public const string Items = "items";

		public const string World = "world";

		public const string Rules = "rules";

		public const string Players = "players";

		public const string NativeGroup = "native";

		public static readonly string[] All = new string[6] { "roles", "potions", "items", "world", "rules", "players" };
	}
	public sealed class ModConfigField
	{
		private readonly object[] _raw;

		public string Label => (string)_raw[0];

		public ModConfigFieldType Type => (ModConfigFieldType)(int)_raw[1];

		public Func<object> Get => (Func<object>)_raw[2];

		public Action<object> Set => (Action<object>)_raw[3];

		public float Min => (float)_raw[4];

		public float Max => (float)_raw[5];

		public string Description
		{
			get
			{
				if (_raw.Length <= 6)
				{
					return null;
				}
				return _raw[6] as string;
			}
		}

		public string[] Options
		{
			get
			{
				if (_raw.Length <= 7)
				{
					return null;
				}
				return _raw[7] as string[];
			}
		}

		internal ModConfigField(object[] raw)
		{
			_raw = raw;
		}

		public float GetRaw()
		{
			object obj = Get();
			switch (Type)
			{
			case ModConfigFieldType.Bool:
				if (!(bool)obj)
				{
					return 0f;
				}
				return 1f;
			case ModConfigFieldType.Int:
			case ModConfigFieldType.Choice:
				return (int)obj;
			default:
				return (float)obj;
			}
		}

		public void SetRaw(float raw)
		{
			switch (Type)
			{
			case ModConfigFieldType.Bool:
				Set(raw != 0f);
				break;
			case ModConfigFieldType.Int:
			case ModConfigFieldType.Choice:
				Set((int)Math.Round(raw));
				break;
			default:
				Set(raw);
				break;
			}
		}

		public string Format(float raw)
		{
			switch (Type)
			{
			case ModConfigFieldType.Bool:
				if (raw == 0f)
				{
					return Translations.Text("Non", "No", "Nein", "No", "Hayır", "No");
				}
				return Translations.Text("Oui", "Yes", "Ja", "Sí", "Evet", "Sì");
			case ModConfigFieldType.Int:
				return ((int)Math.Round(raw)).ToString();
			case ModConfigFieldType.Choice:
			{
				int num = (int)Math.Round(raw);
				string[] options = Options;
				if (options == null || num < 0 || num >= options.Length)
				{
					return num.ToString();
				}
				return options[num];
			}
			default:
				return raw.ToString("0.##");
			}
		}
	}
	public sealed class ModConfigSection
	{
		private readonly object[] _raw;

		public string ModName => (string)_raw[0];

		public Func<bool> GetEnabled => (Func<bool>)_raw[1];

		public Action<bool> SetEnabled => (Action<bool>)_raw[2];

		private List<object[]> RawFields => (List<object[]>)_raw[3];

		public string ChapterId => (_raw[4] as string) ?? "rules";

		public string Description => _raw[5] as string;

		public string WikiText
		{
			get
			{
				if (_raw.Length <= 6 || !(_raw[6] is string[] array))
				{
					return null;
				}
				return Translations.Text(array[0], array[1], array[2], array[3], array[4], array[5]);
			}
		}

		public string Group
		{
			get
			{
				if (_raw.Length <= 7)
				{
					return null;
				}
				return _raw[7] as string;
			}
		}

		public string RoleKey
		{
			get
			{
				if (_raw.Length <= 8)
				{
					return null;
				}
				return _raw[8] as string;
			}
		}

		public bool IsInfo
		{
			get
			{
				bool flag = default(bool);
				int num;
				if (_raw.Length > 9)
				{
					object obj = _raw[9];
					if (obj is bool)
					{
						flag = (bool)obj;
						num = 1;
					}
					else
					{
						num = 0;
					}
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
		}

		public string DisplayName
		{
			get
			{
				if (!ModName.StartsWith("Lycans ", StringComparison.Ordinal))
				{
					return ModName;
				}
				return ModName.Substring(7);
			}
		}

		public IReadOnlyList<ModConfigField> Fields => RawFields.Select((object[] f) => new ModConfigField(f)).ToArray();

		internal ModConfigSection(object[] raw)
		{
			_raw = raw;
		}

		public ModConfigSection ForRole(string roleKey)
		{
			_raw[8] = roleKey;
			return this;
		}

		public ModConfigSection InGroup(string group)
		{
			_raw[7] = group;
			return this;
		}

		public ModConfigSection Chapter(string chapterId, string description = null)
		{
			_raw[4] = chapterId;
			_raw[5] = description;
			return this;
		}

		public ModConfigSection Wiki(string fr, string en = null, string de = null, string es = null, string tr = null, string it = null)
		{
			_raw[6] = new string[6] { fr, en, de, es, tr, it };
			return this;
		}

		public ModConfigSection AddBool(string label, Func<bool> get, Action<bool> set, string description = null)
		{
			return Add(label, ModConfigFieldType.Bool, () => get(), delegate(object v)
			{
				set((bool)v);
			}, 0f, 1f, description, null);
		}

		public ModConfigSection AddInt(string label, Func<int> get, Action<int> set, int min, int max, string description = null)
		{
			return Add(label, ModConfigFieldType.Int, () => get(), delegate(object v)
			{
				set((int)v);
			}, min, max, description, null);
		}

		public ModConfigSection AddFloat(string label, Func<float> get, Action<float> set, float min, float max, string description = null)
		{
			return Add(label, ModConfigFieldType.Float, () => get(), delegate(object v)
			{
				set((float)v);
			}, min, max, description, null);
		}

		public ModConfigSection AddChoice(string label, string[] options, Func<int> get, Action<int> set, string description = null)
		{
			return Add(label, ModConfigFieldType.Choice, () => get(), delegate(object v)
			{
				set((int)v);
			}, 0f, options.Length - 1, description, options);
		}

		private ModConfigSection Add(string label, ModConfigFieldType type, Func<object> get, Action<object> set, float min, float max, string description, string[] options)
		{
			RawFields.Add(new object[8]
			{
				label,
				(int)type,
				get,
				set,
				min,
				max,
				description,
				options
			});
			return this;
		}
	}
	public static class ModConfigRegistry
	{
		private const string SectionsKey = "lycans.mods.config.sections.v2";

		private static readonly object Lock = new object();

		public static IReadOnlyList<ModConfigSection> Sections
		{
			get
			{
				lock (Lock)
				{
					return (from s in GetOrCreate()
						orderby (string)s[0]
						select new ModConfigSection(s)).ToArray();
				}
			}
		}

		public static ModConfigSection RegisterMod(string modName, Func<bool> getEnabled, Action<bool> setEnabled)
		{
			lock (Lock)
			{
				List<object[]> orCreate = GetOrCreate();
				object[] array = orCreate.FirstOrDefault((object[] s) => (string)s[0] == modName);
				if (array != null)
				{
					return new ModConfigSection(array);
				}
				object[] array2 = new object[10]
				{
					modName,
					getEnabled,
					setEnabled,
					new List<object[]>(),
					null,
					null,
					null,
					null,
					null,
					false
				};
				orCreate.Add(array2);
				return new ModConfigSection(array2);
			}
		}

		public static ModConfigSection RegisterInfo(string name)
		{
			ModConfigSection result = RegisterMod(name, () => true, null);
			lock (Lock)
			{
				GetOrCreate().First((object[] s) => (string)s[0] == name)[9] = true;
				return result;
			}
		}

		private static List<object[]> GetOrCreate()
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.config.sections.v2") is List<object[]> result)
			{
				return result;
			}
			List<object[]> list = new List<object[]>();
			AppDomain.CurrentDomain.SetData("lycans.mods.config.sections.v2", list);
			return list;
		}
	}
	public static class ModFiles
	{
		private static readonly Dictionary<string, string> Cache = new Dictionary<string, string>();

		public static string ModDirectory => Path.GetDirectoryName(typeof(ModFiles).Assembly.Location) ?? Paths.PluginPath;

		public static string Resolve(string relativePath)
		{
			if (Path.IsPathRooted(relativePath))
			{
				if (!File.Exists(relativePath))
				{
					return null;
				}
				return relativePath;
			}
			if (Cache.TryGetValue(relativePath, out var value) && File.Exists(value))
			{
				return value;
			}
			foreach (string item in Roots())
			{
				string path = Path.Combine(item, relativePath);
				if (File.Exists(path))
				{
					return Cache[relativePath] = Path.GetFullPath(path);
				}
			}
			return null;
		}

		private static IEnumerable<string> Roots()
		{
			yield return ModDirectory;
			yield return Paths.PluginPath;
			string[] array;
			try
			{
				array = Directory.GetDirectories(Paths.PluginPath);
			}
			catch (Exception)
			{
				array = new string[0];
			}
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				yield return array2[i];
			}
			yield return Paths.GameRootPath;
			yield return Paths.BepInExRootPath;
		}
	}
	public static class ModNetworkHub
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<Type, string> <>9__9_0;

			public static Func<string, string> <>9__9_1;

			public static hook_Awake <>9__12_0;

			public static hook_Spawned <>9__12_1;

			internal string <get_RegisteredTypeNames>b__9_0(Type t)
			{
				return t.FullName;
			}

			internal string <get_RegisteredTypeNames>b__9_1(string n)
			{
				return n;
			}

			internal void <InstallSpawnHookOnce>b__12_0(orig_Awake orig, GameManager self)
			{
				try
				{
					EnsureRegisteredInPrefabTable();
				}
				catch (Exception ex)
				{
					Log.Error("[ModNetworkHub] Échec de l'enregistrement du préfab du carrier : " + ex);
				}
				orig.Invoke(self);
			}

			internal void <InstallSpawnHookOnce>b__12_1(orig_Spawned orig, GameManager self)
			{
				orig.Invoke(self);
				try
				{
					OnGameManagerSpawned(self);
				}
				catch (Exception ex)
				{
					Log.Error("[ModNetworkHub] Échec de la mise en place du carrier réseau : " + ex);
				}
			}
		}

		private const string RegisteredTypesKey = "lycans.mods.network.types";

		private const string HookInstalledKey = "lycans.mods.network.hookinstalled";

		private const string CarrierKey = "lycans.mods.network.carrier";

		private const string PrefabIdKey = "lycans.mods.network.prefabid";

		private const string CarrierObjectName = "LycansModNetworkCarrier";

		private static readonly object Lock = new object();

		private static float _nextLookup;

		public static IReadOnlyList<string> RegisteredTypeNames
		{
			get
			{
				lock (Lock)
				{
					return (from t in GetOrCreate<List<Type>>("lycans.mods.network.types")
						select t.FullName).OrderBy<string, string>((string n) => n, StringComparer.Ordinal).ToArray();
				}
			}
		}

		public static NetworkObject Carrier
		{
			get
			{
				object? data = AppDomain.CurrentDomain.GetData("lycans.mods.network.carrier");
				NetworkObject val = (NetworkObject)((data is NetworkObject) ? data : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				if (Time.unscaledTime < _nextLookup)
				{
					return null;
				}
				_nextLookup = Time.unscaledTime + 0.5f;
				NetworkObject[] array = Object.FindObjectsOfType<NetworkObject>();
				foreach (NetworkObject val2 in array)
				{
					if ((Object)(object)val2 != (Object)null && val2.IsValid && ((Object)val2).name.StartsWith("LycansModNetworkCarrier", StringComparison.Ordinal))
					{
						AppDomain.CurrentDomain.SetData("lycans.mods.network.carrier", val2);
						return val2;
					}
				}
				return null;
			}
		}

		public static void Register<T>() where T : NetworkBehaviour
		{
			lock (Lock)
			{
				List<Type> orCreate = GetOrCreate<List<Type>>("lycans.mods.network.types");
				if (!orCreate.Contains(typeof(T)))
				{
					orCreate.Add(typeof(T));
				}
				InstallSpawnHookOnce();
			}
		}

		private static void InstallSpawnHookOnce()
		{
			//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_005c: Expected O, but got Unknown
			//IL_0075: 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_0080: Expected O, but got Unknown
			object data = AppDomain.CurrentDomain.GetData("lycans.mods.network.hookinstalled");
			bool flag = default(bool);
			int num;
			if (data is bool)
			{
				flag = (bool)data;
				num = 1;
			}
			else
			{
				num = 0;
			}
			if (((uint)num & (flag ? 1u : 0u)) != 0)
			{
				return;
			}
			AppDomain.CurrentDomain.SetData("lycans.mods.network.hookinstalled", true);
			object obj = <>c.<>9__12_0;
			if (obj == null)
			{
				hook_Awake val = delegate(orig_Awake orig, GameManager self)
				{
					try
					{
						EnsureRegisteredInPrefabTable();
					}
					catch (Exception ex)
					{
						Log.Error("[ModNetworkHub] Échec de l'enregistrement du préfab du carrier : " + ex);
					}
					orig.Invoke(self);
				};
				<>c.<>9__12_0 = val;
				obj = (object)val;
			}
			GameManager.Awake += (hook_Awake)obj;
			object obj2 = <>c.<>9__12_1;
			if (obj2 == null)
			{
				hook_Spawned val2 = delegate(orig_Spawned orig, GameManager self)
				{
					orig.Invoke(self);
					try
					{
						OnGameManagerSpawned(self);
					}
					catch (Exception ex)
					{
						Log.Error("[ModNetworkHub] Échec de la mise en place du carrier réseau : " + ex);
					}
				};
				<>c.<>9__12_1 = val2;
				obj2 = (object)val2;
			}
			GameManager.Spawned += (hook_Spawned)obj2;
		}

		private static void OnGameManagerSpawned(GameManager self)
		{
			//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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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)
			if (((SimulationBehaviour)self).Runner.SessionInfo.IsOpen && ((SimulationBehaviour)self).Runner.IsServer)
			{
				EnsureRegisteredInPrefabTable();
				NetworkPrefabId val = (NetworkPrefabId)AppDomain.CurrentDomain.GetData("lycans.mods.network.prefabid");
				NetworkObject data = ((SimulationBehaviour)self).Runner.Spawn(val, (Vector3?)Vector3.zero, (Quaternion?)Quaternion.identity, (PlayerRef?)null, (OnBeforeSpawned)null, (NetworkObjectPredictionKey?)null, true, (NetworkObject)null);
				AppDomain.CurrentDomain.SetData("lycans.mods.network.carrier", data);
				Log.Info("[ModNetworkHub] Carrier réseau spawn côté hôte avec " + GetOrCreate<List<Type>>("lycans.mods.network.types").Count + " composant(s) de mod.");
			}
		}

		private static void EnsureRegisteredInPrefabTable()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0095: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (AppDomain.CurrentDomain.GetData("lycans.mods.network.prefabid") != null)
			{
				return;
			}
			GameObject val = new GameObject("LycansModNetworkCarrier");
			val.AddComponent<NetworkObject>();
			foreach (Type item in GetOrCreate<List<Type>>("lycans.mods.network.types"))
			{
				val.AddComponent(item);
			}
			Object.DontDestroyOnLoad((Object)(object)val);
			NetworkObject component = val.GetComponent<NetworkObject>();
			component.NetworkedBehaviours = val.GetComponents<NetworkBehaviour>();
			component.NetworkGuid = new NetworkObjectGuid(ToGuid("LycansModNetworkCarrier").ToString());
			NetworkPrefabSourceStatic val2 = new NetworkPrefabSourceStatic
			{
				PrefabReference = component
			};
			NetworkPrefabId val3 = default(NetworkPrefabId);
			if (!NetworkProjectConfig.Global.PrefabTable.TryAdd(component.NetworkGuid, (INetworkPrefabSource)(object)val2, ref val3))
			{
				throw new InvalidOperationException("[ModNetworkHub] Carrier déjà présent dans la table de préfabs Fusion.");
			}
			AppDomain.CurrentDomain.SetData("lycans.mods.network.prefabid", val3);
		}

		private static Guid ToGuid(string value)
		{
			using MD5 mD = MD5.Create();
			return new Guid(mD.ComputeHash(Encoding.UTF8.GetBytes(value)));
		}

		private static T GetOrCreate<T>(string key) where T : class, new()
		{
			if (AppDomain.CurrentDomain.GetData(key) is T result)
			{
				return result;
			}
			T val = new T();
			AppDomain.CurrentDomain.SetData(key, val);
			return val;
		}
	}
	public enum ProposalStatus
	{
		Empty,
		PendingHost,
		Voting,
		Accepted,
		Rejected
	}
	public readonly struct ProposalSlot
	{
		public readonly int Index;

		public readonly ProposalStatus Status;

		public readonly string ModName;

		public readonly string FieldLabel;

		public readonly float OldValueRaw;

		public readonly float NewValueRaw;

		public readonly int AuthorPlayerId;

		public readonly int VotesFor;

		public readonly int VotesAgainst;

		public ProposalSlot(int index, ProposalStatus status, string modName, string fieldLabel, float oldValueRaw, float newValueRaw, int authorPlayerId, int votesFor, int votesAgainst)
		{
			Index = index;
			Status = status;
			ModName = modName;
			FieldLabel = fieldLabel;
			OldValueRaw = oldValueRaw;
			NewValueRaw = newValueRaw;
			AuthorPlayerId = authorPlayerId;
			VotesFor = votesFor;
			VotesAgainst = votesAgainst;
		}
	}
	public static class ModProposals
	{
		public const string EnabledField = "Activé";

		private const string SubmitKey = "lycans.mods.proposals.submit";

		private const string VoteKey = "lycans.mods.proposals.vote";

		private const string DecideKey = "lycans.mods.proposals.decide";

		private const string CloseKey = "lycans.mods.proposals.close";

		private const string ListKey = "lycans.mods.proposals.list";

		public static bool IsAvailable => AppDomain.CurrentDomain.GetData("lycans.mods.proposals.list") != null;

		public static void PublishImplementation(Action<int, int, float, float> submit, Action<int, bool> vote, Action<int, bool> hostDecide, Action<int> hostCloseVote, Func<IReadOnlyList<ProposalSlot>> list)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.proposals.submit", submit);
			AppDomain.CurrentDomain.SetData("lycans.mods.proposals.vote", vote);
			AppDomain.CurrentDomain.SetData("lycans.mods.proposals.decide", hostDecide);
			AppDomain.CurrentDomain.SetData("lycans.mods.proposals.close", hostCloseVote);
			AppDomain.CurrentDomain.SetData("lycans.mods.proposals.list", (Func<object[][]>)delegate
			{
				IReadOnlyList<ProposalSlot> readOnlyList = list();
				object[][] array = new object[readOnlyList.Count][];
				for (int i = 0; i < readOnlyList.Count; i++)
				{
					ProposalSlot proposalSlot = readOnlyList[i];
					array[i] = new object[9]
					{
						proposalSlot.Index,
						(int)proposalSlot.Status,
						proposalSlot.ModName,
						proposalSlot.FieldLabel,
						proposalSlot.OldValueRaw,
						proposalSlot.NewValueRaw,
						proposalSlot.AuthorPlayerId,
						proposalSlot.VotesFor,
						proposalSlot.VotesAgainst
					};
				}
				return array;
			});
		}

		public static void Submit(string modName, string fieldLabel, float oldValueRaw, float newValueRaw)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.proposals.submit") is Action<int, int, float, float> action)
			{
				action(Hash(modName), Hash(fieldLabel), oldValueRaw, newValueRaw);
			}
			else
			{
				Log.Info("[ModProposals] Submit ignoré : mod_council non chargé.");
			}
		}

		public static void Vote(int slotIndex, bool voteFor)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.proposals.vote") is Action<int, bool> action)
			{
				action(slotIndex, voteFor);
			}
		}

		public static void HostDecide(int slotIndex, bool approve)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.proposals.decide") is Action<int, bool> action)
			{
				action(slotIndex, approve);
			}
		}

		public static void HostCloseVote(int slotIndex)
		{
			if (AppDomain.CurrentDomain.GetData("lycans.mods.proposals.close") is Action<int> action)
			{
				action(slotIndex);
			}
		}

		public static IReadOnlyList<ProposalSlot> List()
		{
			if (!(AppDomain.CurrentDomain.GetData("lycans.mods.proposals.list") is Func<object[][]> func))
			{
				return Array.Empty<ProposalSlot>();
			}
			object[][] array = func();
			ProposalSlot[] array2 = new ProposalSlot[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				object[] array3 = array[i];
				array2[i] = new ProposalSlot((int)array3[0], (ProposalStatus)(int)array3[1], (string)array3[2], (string)array3[3], (float)array3[4], (float)array3[5], (int)array3[6], (int)array3[7], (int)array3[8]);
			}
			return array2;
		}

		public static int Hash(string value)
		{
			uint num = 2166136261u;
			foreach (char c in value)
			{
				num ^= c;
				num *= 16777619;
			}
			return (int)num;
		}
	}
	public static class ModRegistry
	{
		private const string CapabilitiesKey = "lycans.mods.capabilities";

		private const string SubscribersKey = "lycans.mods.subscribers";

		private static readonly object Lock = new object();

		public static void Register(string modGuid, params string[] capabilities)
		{
			lock (Lock)
			{
				HashSet<string> orCreate = GetOrCreate<HashSet<string>>("lycans.mods.capabilities");
				foreach (string item in capabilities)
				{
					orCreate.Add(item);
				}
			}
		}

		public static bool Has(string capability)
		{
			lock (Lock)
			{
				return GetOrCreate<HashSet<string>>("lycans.mods.capabilities").Contains(capability);
			}
		}

		public static IReadOnlyCollection<string> AllCapabilities()
		{
			lock (Lock)
			{
				return (IReadOnlyCollection<string>)(object)GetOrCreate<HashSet<string>>("lycans.mods.capabilities").ToArray();
			}
		}

		public static void Subscribe<T>(Action<T> handler)
		{
			lock (Lock)
			{
				GetOrCreate<Dictionary<Type, List<Delegate>>>("lycans.mods.subscribers").GetOrAdd(typeof(T)).Add(handler);
			}
		}

		public static void Unsubscribe<T>(Action<T> handler)
		{
			lock (Lock)
			{
				if (GetOrCreate<Dictionary<Type, List<Delegate>>>("lycans.mods.subscribers").TryGetValue(typeof(T), out var value))
				{
					value.Remove(handler);
				}
			}
		}

		public static void Publish<T>(T payload)
		{
			Delegate[] array;
			lock (Lock)
			{
				if (!GetOrCreate<Dictionary<Type, List<Delegate>>>("lycans.mods.subscribers").TryGetValue(typeof(T), out var value))
				{
					return;
				}
				array = value.ToArray();
			}
			Delegate[] array2 = array;
			foreach (Delegate obj in array2)
			{
				try
				{
					((Action<T>)obj)(payload);
				}
				catch (Exception ex)
				{
					Log.Error("[ModRegistry] Abonné en erreur pour " + typeof(T).Name + " : " + ex);
				}
			}
		}

		private static T GetOrCreate<T>(string key) where T : class, new()
		{
			if (AppDomain.CurrentDomain.GetData(key) is T result)
			{
				return result;
			}
			T val = new T();
			AppDomain.CurrentDomain.SetData(key, val);
			return val;
		}

		private static List<Delegate> GetOrAdd(this Dictionary<Type, List<Delegate>> dict, Type key)
		{
			if (!dict.TryGetValue(key, out var value))
			{
				value = (dict[key] = new List<Delegate>());
			}
			return value;
		}
	}
	public sealed class MovementContext
	{
		private readonly IDictionary<string, object> _data;

		private float[] Values => (float[])_data["values"];

		public PlayerController Player => (PlayerController)_data["player"];

		public CharacterMovementHandler Handler => (CharacterMovementHandler)_data["handler"];

		public float X
		{
			get
			{
				return Values[0];
			}
			set
			{
				Values[0] = value;
			}
		}

		public float Y
		{
			get
			{
				return Values[1];
			}
			set
			{
				Values[1] = value;
			}
		}

		public float Speed
		{
			get
			{
				return Values[2];
			}
			set
			{
				Values[2] = value;
			}
		}

		public bool Teleported => (bool)_data["teleported"];

		public bool Cancel
		{
			get
			{
				return HookPipeline.IsCancelled(_data);
			}
			set
			{
				_data["cancel"] = HookPipeline.Box(value);
			}
		}

		internal MovementContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class MovementRules
	{
		public const string Method = "CharacterMovementHandler.FixedUpdateNetwork";

		public static void Before(int priority, string owner, Action<MovementContext> step)
		{
			HookPipeline.Register("CharacterMovementHandler.FixedUpdateNetwork", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				step(new MovementContext(data));
			});
		}

		public static void After(int priority, string owner, Action<MovementContext> step)
		{
			HookPipeline.Register("CharacterMovementHandler.FixedUpdateNetwork", priority, owner, HookPhase.After, delegate(IDictionary<string, object> data)
			{
				step(new MovementContext(data));
			});
		}

		public static IDictionary<string, object> NewData()
		{
			return new Dictionary<string, object> { ["values"] = new float[3] };
		}

		public static void Reset(IDictionary<string, object> data, CharacterMovementHandler handler, PlayerController player, float x, float y, float speed, bool teleported)
		{
			data["handler"] = handler;
			data["player"] = player;
			data["teleported"] = HookPipeline.Box(teleported);
			data["cancel"] = HookPipeline.False;
			float[] obj = (float[])data["values"];
			obj[0] = x;
			obj[1] = y;
			obj[2] = speed;
		}
	}
	public static class NetworkedWeaving
	{
		public unsafe static bool GetBool(int* ptr, int word)
		{
			return *CheckedPtr(ptr, word) != 0;
		}

		public unsafe static void SetBool(int* ptr, int word, bool value)
		{
			*CheckedPtr(ptr, word) = (value ? 1 : 0);
		}

		public unsafe static int GetInt(int* ptr, int word)
		{
			return *CheckedPtr(ptr, word);
		}

		public unsafe static void SetInt(int* ptr, int word, int value)
		{
			*CheckedPtr(ptr, word) = value;
		}

		public unsafe static float GetFloat(int* ptr, int word)
		{
			return *(float*)CheckedPtr(ptr, word);
		}

		public unsafe static void SetFloat(int* ptr, int word, float value)
		{
			*(float*)CheckedPtr(ptr, word) = value;
		}

		private unsafe static int* CheckedPtr(int* ptr, int word)
		{
			if (ptr == null)
			{
				throw new InvalidOperationException("Champ réseau lu avant Spawned() : les propriétés [Networked] ne sont valides qu'une fois l'objet spawn.");
			}
			return ptr + word;
		}
	}
	public sealed class ObjectTargetContext
	{
		private readonly IDictionary<string, object> _data;

		public PlayerController Player => (PlayerController)_data["player"];

		public GameObject Target
		{
			get
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Expected O, but got Unknown
				return (GameObject)_data["target"];
			}
			set
			{
				_data["target"] = value;
			}
		}

		public float Distance => (float)_data["distance"];

		public bool Offered => (bool)_data["offered"];

		internal ObjectTargetContext(IDictionary<string, object> data)
		{
			_data = data;
		}
	}
	public static class ObjectTargetRules
	{
		public const string Method = "PlayerController.UpdateRayCast";

		public static void Offer(int priority, string owner, Func<ObjectTargetContext, bool> offer)
		{
			HookPipeline.Register("PlayerController.UpdateRayCast", priority, owner, HookPhase.Before, delegate(IDictionary<string, object> data)
			{
				if (!(bool)data["offered"] && offer(new ObjectTargetContext(data)))
				{
					data["offered"] = HookPipeline.True;
				}
			});
		}

		public static IDictionary<string, object> NewData()
		{
			return new Dictionary<string, object>();
		}

		public static void Reset(IDictionary<string, object> data, PlayerController player, GameObject target, float distance)
		{
			data["player"] = player;
			data["target"] = target;
			data["distance"] = distance;
			data["offered"] = HookPipeline.False;
			data["cancel"] = HookPipeline.False;
		}
	}
	public static class PlayerColors
	{
		private const string GetKey = "lycans.mods.colors.get";

		private const string SetKey = "lycans.mods.colors.set";

		private const string CountKey = "lycans.mods.colors.count";

		public static bool IsAvailable => AppDomain.CurrentDomain.GetData("lycans.mods.colors.get") != null;

		public static int Count
		{
			get
			{
				if (!(AppDomain.CurrentDomain.GetData("lycans.mods.colors.count") is Func<int> func))
				{
					return 0;
				}
				return func();
			}
		}

		public static void PublishImplementation(Func<int, int> get, Action<int, int> set, Func<int> count)
		{
			AppDomain.CurrentDomain.SetData("lycans.mods.colors.get", get);
			AppDomain.CurrentDomain.SetData("lycans.mods.colors.set", set);
			AppDomain.CurrentDomain.SetData("lycans.mods.colors.count", count);
		}

		public static int Get(PlayerController player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0;
			}
			if (!(AppDomain.CurrentDomain.GetData("lycans.mods.colors.get") is Func<int, int> func))
			{
				return player.Index;
			}
			return func(player.Index);
		}

		public static void Set(Playe