Decompiled source of Mimesis PowerUps v0.9.0

Mods/MimesisPowerUps.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Bifrost.ConstEnum;
using Bifrost.Cooked;
using DarkTonic.MasterAudio;
using DunGen;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Utils;
using MimesisPowerUps;
using MimesisPowerUps.Core;
using MimesisPowerUps.Integration;
using MimesisPowerUps.UI;
using Mimic;
using Mimic.Actors;
using Mimic.Audio;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Pathfinding;
using ReluProtocol;
using ReluProtocol.C2S;
using ReluProtocol.Enum;
using ReluServerBase.Threading;
using Steamworks;
using Unity.Cinemachine;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(ModEntry), "Mimesis Power-Ups", "0.9.0", "Mirou", null)]
[assembly: MelonGame(null, "MIMESIS")]
[assembly: AssemblyFileVersion("0.9.0.0")]
[assembly: AssemblyVersion("0.9.0.0")]
namespace MimesisPowerUps
{
	public sealed class ModEntry : MelonMod
	{
		private SessionBridge session;

		private GuitarMusicController guitar;

		private DateTime nextError = DateTime.MinValue;

		public override void OnInitializeMelon()
		{
			session = new SessionBridge(delegate(string text2)
			{
				((MelonBase)this).LoggerInstance.Msg(text2);
			}, ((MelonBase)this).HarmonyInstance);
			try
			{
				string text = Path.Combine(MelonEnvironment.UserDataDirectory, "MimesisPowerUps");
				BundledGuitarSongs.Install(Path.GetDirectoryName(typeof(ModEntry).Assembly.Location), text, delegate(string text2)
				{
					((MelonBase)this).LoggerInstance.Msg(text2);
				});
				guitar = new GuitarMusicController(text, delegate(string text2)
				{
					((MelonBase)this).LoggerInstance.Msg(text2);
				}, session.SendGuitarMessage);
				guitar.Install(((MelonBase)this).HarmonyInstance);
				session.GuitarMessageReceived = guitar.Receive;
			}
			catch (Exception ex)
			{
				if (guitar != null)
				{
					guitar.Dispose();
				}
				guitar = null;
				((MelonBase)this).LoggerInstance.Warning("Guitare Suno indisponible : " + ex.Message);
			}
			((MelonBase)this).LoggerInstance.Msg("Mimesis Power-Ups 0.9.0 — Par Mirou, développé avec une IA. Cellules de Stats, Prop Hunt et guitare Suno.");
		}

		public override void OnUpdate()
		{
			try
			{
				if (session != null)
				{
					session.Update();
				}
				if (guitar != null)
				{
					guitar.Update();
				}
			}
			catch (Exception ex)
			{
				if (DateTime.UtcNow >= nextError)
				{
					((MelonBase)this).LoggerInstance.Error(ex.ToString());
					nextError = DateTime.UtcNow.AddSeconds(10.0);
				}
			}
		}

		public override void OnLateUpdate()
		{
			if (session != null)
			{
				session.LateUpdate();
			}
			if (GameAdapter.Instance != null)
			{
				GameAdapter.Instance.EnforceInputCapture();
			}
		}

		public override void OnGUI()
		{
			if (GameAdapter.Instance != null)
			{
				GameAdapter.Instance.EnforceInputCapture();
			}
			if (session != null)
			{
				session.Draw();
			}
		}

		public override void OnDeinitializeMelon()
		{
			try
			{
				if (guitar != null)
				{
					guitar.Dispose();
				}
			}
			finally
			{
				if (session != null)
				{
					session.Dispose();
				}
			}
		}
	}
}
namespace MimesisPowerUps.Integration
{
	public static class BundledGuitarSongs
	{
		private static readonly string[] Names = new string[2] { "Primary Key Guitar.mp3", "Le bout du tunnel Guitar.mp3" };

		private static readonly string[] Hashes = new string[2] { "46B3E395C50C7747D2D9FD322651D78FD09A4ED5AA08CBF04C67919D7ADD9C59", "603384832324A309345E37BFE99EF822712ED946F2BBBB20071C7AC42458828C" };

		private const long MaximumBytes = 16777216L;

		public static int Install(string assemblyDirectory, string persistentDataRoot, Action<string> logger)
		{
			int num = 0;
			try
			{
				if (string.IsNullOrWhiteSpace(assemblyDirectory) || string.IsNullOrWhiteSpace(persistentDataRoot))
				{
					return 0;
				}
				string text = Path.Combine(Path.GetFullPath(assemblyDirectory), "GuitarMusic", "Songs");
				if (!Directory.Exists(text))
				{
					return 0;
				}
				string text2 = Path.Combine(Path.GetFullPath(persistentDataRoot), "GuitarMusic", "Songs");
				for (int i = 0; i < Names.Length; i++)
				{
					string text3 = null;
					try
					{
						string text4 = Path.Combine(text2, Names[i]);
						if (File.Exists(text4))
						{
							continue;
						}
						string text5 = Path.Combine(text, Names[i]);
						if (!File.Exists(text5))
						{
							continue;
						}
						FileInfo fileInfo = new FileInfo(text5);
						if ((fileInfo.Attributes & FileAttributes.ReparsePoint) != FileAttributes.None || fileInfo.Length == 0L || fileInfo.Length > 16777216)
						{
							throw new InvalidDataException("Ressource audio invalide.");
						}
						Directory.CreateDirectory(text2);
						text3 = Path.Combine(text2, ".bundled-song-" + Guid.NewGuid().ToString("N") + ".tmp");
						File.Copy(text5, text3, overwrite: false);
						using (FileStream inputStream = new FileStream(text3, FileMode.Open, FileAccess.Read, FileShare.Read))
						{
							using SHA256 sHA = SHA256.Create();
							if (!string.Equals(BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", ""), Hashes[i], StringComparison.Ordinal))
							{
								throw new InvalidDataException("Empreinte audio incorrecte.");
							}
						}
						File.Move(text3, text4);
						text3 = null;
						num++;
					}
					catch (Exception ex)
					{
						Log(logger, "Guitare : import du morceau fourni ignoré : " + Names[i] + " (" + ex.GetType().Name + ").");
					}
					finally
					{
						if (text3 != null)
						{
							try
							{
								File.Delete(text3);
							}
							catch
							{
							}
						}
					}
				}
				if (num > 0)
				{
					Log(logger, "Guitare : " + num + " morceau(x) fourni(s) installé(s).");
				}
			}
			catch (Exception ex2)
			{
				Log(logger, "Guitare : ressources fournies indisponibles (" + ex2.GetType().Name + ").");
			}
			return num;
		}

		private static void Log(Action<string> logger, string text)
		{
			if (logger == null)
			{
				return;
			}
			try
			{
				logger(text);
			}
			catch
			{
			}
		}
	}
	internal static class CheatCommandParser
	{
		public static bool TryParse(string text, string localPlayerId, IList<PlayerRow> players, IList<CheatItemView> items, out CheatRequest request, out string error)
		{
			return TryParse(text, localPlayerId, players, items, null, out request, out error);
		}

		public static bool TryParse(string text, string localPlayerId, IList<PlayerRow> players, IList<CheatItemView> items, IList<CheatMonsterView> monsters, out CheatRequest request, out string error)
		{
			request = null;
			error = "";
			if (string.IsNullOrWhiteSpace(text))
			{
				error = "Saisis une commande : spawn, xp, stat, cellule ou monstre.";
				return false;
			}
			if (text.Length > 256)
			{
				error = "La commande est limitée à 256 caractères.";
				return false;
			}
			foreach (char c in text)
			{
				if (char.IsControl(c) && c != '\t')
				{
					error = "Utilise une seule ligne pour la commande.";
					return false;
				}
			}
			string text2 = text.Trim();
			if (text2.StartsWith("/", StringComparison.Ordinal))
			{
				text2 = text2.Substring(1);
			}
			if (!Tokenize(text2, out var tokens))
			{
				error = "Ferme les guillemets autour des pseudos ou des noms d'objets.";
				return false;
			}
			if (tokens.Count == 0)
			{
				error = "Saisis une commande : spawn, xp, stat, cellule ou monstre.";
				return false;
			}
			string text3 = Normalize(tokens[0]);
			int num;
			switch (text3)
			{
			case "monstre":
			{
				if (tokens.Count < 2)
				{
					error = "Usage : monstre <identifiant ou nom> ; monstre stop pour revenir au joueur.";
					return false;
				}
				string text4 = string.Join(" ", tokens.GetRange(1, tokens.Count - 1).ToArray());
				if (Normalize(text4) == "stop" || Normalize(text4) == "retour")
				{
					request = new CheatRequest
					{
						Kind = CheatCommandKind.StopMonsterControl
					};
					return true;
				}
				if (!ResolveMonster(text4, monsters, out var id2, out error))
				{
					return false;
				}
				request = new CheatRequest
				{
					Kind = CheatCommandKind.ControlMonster,
					MonsterId = id2
				};
				return true;
			}
			case "spawn":
			{
				if (tokens.Count < 2)
				{
					error = "Usage : spawn <identifiant ou nom d'objet>.";
					return false;
				}
				if (!ResolveItem(string.Join(" ", tokens.GetRange(1, tokens.Count - 1).ToArray()), items, out var id, out error))
				{
					return false;
				}
				request = new CheatRequest
				{
					Kind = CheatCommandKind.SpawnItem,
					ItemId = id
				};
				return true;
			}
			default:
				num = 3;
				break;
			case "stat":
				num = 4;
				break;
			}
			int num2 = num;
			if (text3 != "xp" && text3 != "stat" && text3 != "cellule")
			{
				error = "Commande inconnue. Utilise spawn, xp, stat, cellule ou monstre.";
				return false;
			}
			if ((text3 == "cellule") ? (tokens.Count < num2) : (tokens.Count != num2))
			{
				error = ((text3 == "stat") ? "Usage : stat <moi, identifiant ou pseudo> <statistique> <valeur>." : ((text3 == "xp") ? "Usage : xp <moi, identifiant ou pseudo> <1 à 1 000 000>." : "Usage : cellule <moi, identifiant ou pseudo> <rareté>."));
				error += " Mets un pseudo contenant des espaces entre guillemets.";
				return false;
			}
			if (!ResolvePlayer(tokens[1], localPlayerId, players, out var id3, out error))
			{
				return false;
			}
			if (text3 == "xp")
			{
				if (!long.TryParse(tokens[2], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 1 || result > 1000000)
				{
					error = "L'XP doit être un nombre entier compris entre 1 et 1 000 000.";
					return false;
				}
				request = new CheatRequest
				{
					Kind = CheatCommandKind.GrantXp,
					PlayerId = id3,
					Xp = result
				};
				return true;
			}
			if (text3 == "cellule")
			{
				int num3 = ParseRarity(string.Join(" ", tokens.GetRange(2, tokens.Count - 2).ToArray()));
				if (num3 < 0)
				{
					error = "Raretés : commune, peucommune, rare, epic ou legendaire.";
					return false;
				}
				request = new CheatRequest
				{
					Kind = CheatCommandKind.GiveCell,
					PlayerId = id3,
					RarityIndex = num3
				};
				return true;
			}
			int num4 = ParseStat(tokens[2]);
			if (num4 < 0)
			{
				error = "Statistiques : vie, force, endurance, radiation, vitesse ou capacite.";
				return false;
			}
			NumberStyles style = NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint;
			if ((!double.TryParse(tokens[3], style, CultureInfo.GetCultureInfo("fr-FR"), out var result2) && !double.TryParse(tokens[3], style, CultureInfo.InvariantCulture, out result2)) || double.IsNaN(result2) || double.IsInfinity(result2))
			{
				error = "La valeur de statistique doit être un nombre fini, par exemple 105 ou 105,5.";
				return false;
			}
			Stat stat = (Stat)num4;
			double num5 = StatRules.Minimum(stat);
			double num6 = StatRules.Maximum(stat);
			if (result2 < num5 || result2 > num6)
			{
				error = StatRules.Label(stat) + " : valeur comprise entre " + num5.ToString("0.##", CultureInfo.GetCultureInfo("fr-FR")) + " et " + num6.ToString("0.##", CultureInfo.GetCultureInfo("fr-FR")) + ".";
				return false;
			}
			if (!StatRules.IsPercentage(stat) && result2 != Math.Truncate(result2))
			{
				error = "Les emplacements d'objets utilisent des nombres entiers.";
				return false;
			}
			request = new CheatRequest
			{
				Kind = CheatCommandKind.SetStat,
				PlayerId = id3,
				StatIndex = num4,
				StatValue = result2
			};
			return true;
		}

		private static bool ResolvePlayer(string text, string localPlayerId, IList<PlayerRow> players, out string id, out string error)
		{
			id = "";
			error = "";
			string text2 = Normalize(text);
			bool flag = text2 == "moi";
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (players != null)
			{
				foreach (PlayerRow player in players)
				{
					if (player != null && !string.IsNullOrEmpty(player.Id) && player.Id == (flag ? localPlayerId : text))
					{
						id = player.Id;
						return true;
					}
				}
				if (!flag && text2.Length > 0)
				{
					foreach (PlayerRow player2 in players)
					{
						if (player2 != null && !string.IsNullOrEmpty(player2.Id) && Normalize(player2.Name) == text2)
						{
							hashSet.Add(player2.Id);
						}
					}
				}
			}
			if (hashSet.Count == 1)
			{
				foreach (string item in hashSet)
				{
					id = item;
				}
				return true;
			}
			error = ((hashSet.Count > 1) ? ("Plusieurs joueurs portent ce pseudo. Utilise leur identifiant : " + Sample(hashSet) + ".") : (flag ? "Ton joueur n'est pas encore présent dans la partie." : "Joueur introuvable. Utilise son identifiant ou son pseudo exact entre guillemets."));
			return false;
		}

		private static bool ResolveItem(string text, IList<CheatItemView> items, out int id, out string error)
		{
			id = 0;
			error = "";
			if (int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out var result))
			{
				if (result > 0 && items != null)
				{
					foreach (CheatItemView item in items)
					{
						if (item != null && item.Id == result)
						{
							id = result;
							return true;
						}
					}
				}
				error = "Identifiant d'objet introuvable dans le catalogue.";
				return false;
			}
			string text2 = Normalize(text);
			if (text2.Length == 0)
			{
				error = "Indique un identifiant ou un nom d'objet.";
				return false;
			}
			HashSet<int> hashSet = new HashSet<int>();
			if (items != null)
			{
				foreach (CheatItemView item2 in items)
				{
					if (item2 != null && item2.Id > 0 && Normalize(item2.Name) == text2)
					{
						hashSet.Add(item2.Id);
					}
				}
				if (hashSet.Count == 0)
				{
					foreach (CheatItemView item3 in items)
					{
						if (item3 != null && item3.Id > 0 && Normalize(item3.Name).IndexOf(text2, StringComparison.Ordinal) >= 0)
						{
							hashSet.Add(item3.Id);
						}
					}
				}
			}
			if (hashSet.Count == 1)
			{
				foreach (int item4 in hashSet)
				{
					id = item4;
				}
				return true;
			}
			if (hashSet.Count > 1)
			{
				List<string> list = new List<string>();
				foreach (int item5 in hashSet)
				{
					list.Add(item5.ToString(CultureInfo.InvariantCulture));
				}
				error = "Plusieurs objets correspondent. Utilise un identifiant : " + Sample(list) + ".";
			}
			else
			{
				error = "Objet introuvable. Choisis un identifiant ou un nom dans le catalogue.";
			}
			return false;
		}

		private static bool ResolveMonster(string text, IList<CheatMonsterView> monsters, out int id, out string error)
		{
			List<CheatItemView> list = new List<CheatItemView>();
			if (monsters != null)
			{
				foreach (CheatMonsterView monster in monsters)
				{
					if (monster != null && monster.Id > 0)
					{
						list.Add(new CheatItemView
						{
							Id = monster.Id,
							Name = monster.Name
						});
					}
				}
			}
			if (!ResolveItem(text, list, out id, out error))
			{
				error = error.Replace("objets", "monstres").Replace("objet", "monstre").Replace("Objet", "Monstre");
				return false;
			}
			foreach (CheatMonsterView monster2 in monsters)
			{
				if (monster2 != null && monster2.Id == id && !monster2.CanControl)
				{
					id = 0;
					error = (string.IsNullOrWhiteSpace(monster2.UnavailableReason) ? "Ce monstre ne peut pas être contrôlé dans cette version." : monster2.UnavailableReason);
					return false;
				}
			}
			return true;
		}

		private static string Sample(IEnumerable<string> values)
		{
			List<string> list = new List<string>(values);
			list.Sort(StringComparer.Ordinal);
			string text = string.Join(", ", list.GetRange(0, Math.Min(3, list.Count)).ToArray());
			if (list.Count <= 3)
			{
				return text;
			}
			return text + "…";
		}

		private static int ParseStat(string value)
		{
			switch (Key(value))
			{
			case "vie":
			case "pv":
				return 0;
			case "force":
				return 1;
			case "endurance":
			case "stam":
				return 2;
			case "radiation":
			case "radiations":
			case "radiationmax":
			case "radiationmaximale":
			case "contamination":
				return 3;
			case "vitesse":
				return 4;
			case "capacite":
			case "capacitedobjets":
			case "objets":
				return 5;
			default:
				return -1;
			}
		}

		private static int ParseRarity(string value)
		{
			switch (Key(value))
			{
			case "commune":
				return 0;
			case "peucommune":
				return 1;
			case "rare":
				return 2;
			case "epic":
			case "epique":
				return 3;
			case "legendaire":
				return 4;
			default:
				return -1;
			}
		}

		private static string Key(string value)
		{
			return Normalize(value).Replace(" ", "").Replace("-", "").Replace("_", "")
				.Replace("'", "")
				.Replace("’", "");
		}

		private static string Normalize(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "";
			}
			string text;
			try
			{
				text = value.Trim().Normalize(NormalizationForm.FormD);
			}
			catch (ArgumentException)
			{
				return value.Trim().ToLowerInvariant();
			}
			StringBuilder stringBuilder = new StringBuilder();
			string text2 = text;
			foreach (char c in text2)
			{
				UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
				if (unicodeCategory != UnicodeCategory.NonSpacingMark && unicodeCategory != UnicodeCategory.SpacingCombiningMark && unicodeCategory != UnicodeCategory.EnclosingMark)
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString().Normalize(NormalizationForm.FormC).Replace("œ", "oe");
		}

		private static bool Tokenize(string text, out List<string> tokens)
		{
			tokens = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = false;
			bool flag2 = false;
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (c == '"')
				{
					flag = !flag;
					flag2 = true;
				}
				else if (c == '\\' && flag && i + 1 < text.Length && (text[i + 1] == '"' || text[i + 1] == '\\'))
				{
					stringBuilder.Append(text[++i]);
					flag2 = true;
				}
				else if (char.IsWhiteSpace(c) && !flag)
				{
					if (flag2)
					{
						tokens.Add(stringBuilder.ToString());
						stringBuilder.Length = 0;
						flag2 = false;
					}
				}
				else
				{
					stringBuilder.Append(c);
					flag2 = true;
				}
			}
			if (flag)
			{
				return false;
			}
			if (flag2)
			{
				tokens.Add(stringBuilder.ToString());
			}
			return true;
		}
	}
	public sealed class CheatItemEntry
	{
		public int Id;

		public string Name = "";
	}
	internal static class CheatGameActions
	{
		private static readonly MethodInfo LocalizeItemName = typeof(Hub).GetMethod("GetL10NText", GameAdapter.All, null, new Type[2]
		{
			typeof(string),
			typeof(object[])
		}, null);

		public static List<CheatItemEntry> GetItems()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			List<CheatItemEntry> list = new List<CheatItemEntry>();
			try
			{
				GameAdapter instance = GameAdapter.Instance;
				VWorld world = NativeWorld();
				if (instance == null || !IsCurrentHostContext(instance, world, instance.SaveKey))
				{
					return list;
				}
				ExcelDataManager val = Data();
				if (val == null || val.ItemInfoDict == null)
				{
					return list;
				}
				Enumerator<int, ItemMasterInfo> enumerator = val.ItemInfoDict.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						KeyValuePair<int, ItemMasterInfo> current = enumerator.Current;
						ItemMasterInfo value = current.Value;
						if (CanSpawn(value) && current.Key == value.MasterID)
						{
							list.Add(new CheatItemEntry
							{
								Id = value.MasterID,
								Name = DisplayName(value)
							});
						}
					}
				}
				finally
				{
					((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
				list.Sort(delegate(CheatItemEntry a, CheatItemEntry b)
				{
					int num = StringComparer.CurrentCultureIgnoreCase.Compare(a.Name, b.Name);
					return (num == 0) ? a.Id.CompareTo(b.Id) : num;
				});
			}
			catch
			{
			}
			return list;
		}

		public static void SpawnItem(string expectedSaveKey, int masterId, Action<bool, string> completed)
		{
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			int completedOnce = 0;
			Action<bool, string> finish = delegate(bool success, string message)
			{
				if (Interlocked.Exchange(ref completedOnce, 1) != 0 || completed == null)
				{
					return;
				}
				try
				{
					completed(success, message);
				}
				catch (Exception ex2)
				{
					try
					{
						MelonLogger.Warning("Power-Ups : retour de commande d'objet ignoré (" + ex2.GetType().Name + ").");
					}
					catch
					{
					}
				}
			};
			try
			{
				GameAdapter adapter = GameAdapter.Instance;
				VWorld world = NativeWorld();
				if (!IsCurrentHostContext(adapter, world, expectedSaveKey))
				{
					finish(arg1: false, "Commande réservée à l'hôte de la partie en cours.");
					return;
				}
				if (masterId <= 0)
				{
					finish(arg1: false, "Identifiant d'objet invalide.");
					return;
				}
				ExcelDataManager val = Data();
				ItemMasterInfo val2 = ((val == null) ? null : val.GetItemInfo(masterId));
				if (!CanSpawn(val2) || val2.MasterID != masterId)
				{
					finish(arg1: false, "Cet objet n'existe pas ou ne peut pas apparaître dans le monde.");
					return;
				}
				string actorId = adapter.LocalPlayerId;
				if (!ulong.TryParse(actorId, NumberStyles.None, CultureInfo.InvariantCulture, out var localSteamId) || localSteamId == 0L)
				{
					finish(arg1: false, "Identité de l'hôte indisponible.");
					return;
				}
				VRoomManager manager = world.VRoomManager;
				CommandExecutor val3 = (CommandExecutor)((manager == null) ? null : /*isinst with value type is only supported in some contexts*/);
				if (val3 == null)
				{
					finish(arg1: false, "Le serveur de la partie n'est pas prêt.");
				}
				else if (!val3.Invoke((Command)delegate
				{
					//IL_0191: Unknown result type (might be due to invalid IL or missing references)
					//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
					//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (!IsCurrentHostContext(adapter, world, expectedSaveKey) || adapter.LocalPlayerId != actorId)
						{
							finish(arg1: false, "La partie a changé. Relance la commande dans la nouvelle partie.");
						}
						else
						{
							VPlayer host = null;
							bool ambiguous = false;
							foreach (IVroom item in Rooms(world))
							{
								item.IterateAllPlayer((Action<VPlayer>)delegate(VPlayer player)
								{
									//IL_0027: Unknown result type (might be due to invalid IL or missing references)
									//IL_002d: Invalid comparison between Unknown and I4
									if (player != null && player.SteamID == localSteamId && player.IsHost && !player.Wasted && (int)((VCreature)player).LifeCycle == 1)
									{
										if (host != null && host != player)
										{
											ambiguous = true;
										}
										else
										{
											host = player;
										}
									}
								});
							}
							if (host == null || ambiguous || ((VActor)host).VRoom == null || ((VActor)host).VRoom.RoomManager != manager)
							{
								finish(arg1: false, "L'hôte doit être vivant et présent dans une zone prête.");
							}
							else
							{
								ItemMasterInfo val4 = ((Data() == null) ? null : Data().GetItemInfo(masterId));
								if (!CanSpawn(val4) || val4.MasterID != masterId)
								{
									finish(arg1: false, "Cet objet ne peut pas apparaître dans le monde.");
								}
								else
								{
									PosWithRot val5 = ((((VActor)host).Position == null) ? null : ((VActor)host).Position.Clone());
									if (val5 == null || !Finite(val5.pos.x) || !Finite(val5.pos.y) || !Finite(val5.pos.z))
									{
										finish(arg1: false, "Position de l'hôte indisponible.");
									}
									else
									{
										ItemElement newItemElement = ((VActor)host).VRoom.GetNewItemElement(masterId, false, 1, 0, 0, 0);
										if (newItemElement == null)
										{
											finish(arg1: false, "Le jeu n'a pas pu créer cet objet.");
										}
										else
										{
											int num = ((VActor)host).VRoom.SpawnLootingObject(newItemElement, val5, ((VActor)host).IsIndoor, (ReasonOfSpawn)8, 0, 0, 0L, false, false);
											finish(num != 0, (num == 0) ? "Le jeu a refusé l'apparition de l'objet." : ("Objet créé : " + DisplayName(val4) + " (" + masterId.ToString(CultureInfo.InvariantCulture) + ")."));
										}
									}
								}
							}
						}
					}
					catch (Exception ex2)
					{
						finish(arg1: false, "Apparition impossible (" + ex2.GetType().Name + ").");
					}
				}))
				{
					finish(arg1: false, "Le serveur de la partie est arrêté.");
				}
			}
			catch (Exception ex)
			{
				finish(arg1: false, "Commande impossible (" + ex.GetType().Name + ").");
			}
		}

		private static bool IsCurrentHostContext(GameAdapter adapter, VWorld world, string expectedSaveKey)
		{
			if (adapter != null && adapter == GameAdapter.Instance && world != null && world.Running && adapter.IsHost && !string.IsNullOrEmpty(expectedSaveKey) && adapter.SaveKey == expectedSaveKey && NativeWorld() == world)
			{
				object obj = GameAdapter.Read(adapter, "world");
				return ((obj is VWorld) ? obj : null) == world;
			}
			return false;
		}

		private static VWorld NativeWorld()
		{
			if (!((Object)(object)Hub.s == (Object)null))
			{
				object obj = GameAdapter.Read(Hub.s, "vworld");
				return (VWorld)((obj is VWorld) ? obj : null);
			}
			return null;
		}

		private static ExcelDataManager Data()
		{
			if ((Object)(object)Hub.s == (Object)null)
			{
				return null;
			}
			object obj = GameAdapter.Read(Hub.s, "dataman");
			DataManager val = (DataManager)((obj is DataManager) ? obj : null);
			if (!((Object)(object)val == (Object)null))
			{
				return val.ExcelDataManager;
			}
			return null;
		}

		private static IEnumerable<IVroom> Rooms(VWorld world)
		{
			IDictionary dictionary = ((world == null || world.VRoomManager == null) ? null : (GameAdapter.Read(world.VRoomManager, "_vrooms") as IDictionary));
			if (dictionary == null)
			{
				yield break;
			}
			foreach (DictionaryEntry item in dictionary)
			{
				object? value = item.Value;
				IVroom val = (IVroom)((value is IVroom) ? value : null);
				if (val != null && val.RoomManager == world.VRoomManager)
				{
					yield return val;
				}
			}
		}

		private static bool CanSpawn(ItemMasterInfo item)
		{
			if (item != null && item.MasterID > 0)
			{
				return !string.IsNullOrEmpty(item.LootingObjectID);
			}
			return false;
		}

		private static string DisplayName(ItemMasterInfo item)
		{
			string text = item.Name;
			try
			{
				object obj = (((Object)(object)Hub.s == (Object)null) ? null : GameAdapter.Read(Hub.s, "pdata"));
				if (obj != null)
				{
					MethodInfo method = obj.GetType().GetMethod("GetItemDisplayName", GameAdapter.All, null, new Type[2]
					{
						typeof(int),
						typeof(string)
					}, null);
					if (method != null)
					{
						text = method.Invoke(obj, new object[2] { item.MasterID, text }) as string;
					}
				}
			}
			catch
			{
			}
			string text2 = TranslateName(text);
			if (text2 != null)
			{
				return text2;
			}
			if (!string.Equals(text, item.Name, StringComparison.Ordinal))
			{
				text2 = TranslateName(item.Name);
				if (text2 != null)
				{
					return text2;
				}
			}
			try
			{
				string text3 = item.LootingObjectID.Replace('\\', '/');
				text3 = text3.Substring(text3.LastIndexOf('/') + 1);
				if (text3.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
				{
					text3 = text3.Substring(0, text3.Length - 7);
				}
				string[] array = new string[4] { "equipment_", "miscellnary_", "miscellany_", "consumable_" };
				foreach (string text4 in array)
				{
					if (text3.StartsWith(text4, StringComparison.OrdinalIgnoreCase))
					{
						text3 = text3.Substring(text4.Length);
						break;
					}
				}
				text3 = Regex.Replace(text3, "([a-z0-9])([A-Z])", "$1 $2");
				text3 = Regex.Replace(text3, "[_\\s-]+", " ").Trim();
				if (UsableName(text3) && Regex.IsMatch(text3, "[\\p{L}]"))
				{
					return char.ToUpper(text3[0], CultureInfo.CurrentCulture) + text3.Substring(1);
				}
			}
			catch
			{
			}
			int i = item.MasterID;
			return "Objet " + i.ToString(CultureInfo.InvariantCulture);
		}

		private static string TranslateName(string key)
		{
			if (string.IsNullOrWhiteSpace(key) || LocalizeItemName == null)
			{
				return null;
			}
			try
			{
				string text = LocalizeItemName.Invoke(null, new object[2]
				{
					key,
					new object[0]
				}) as string;
				return UsableName(text) ? Regex.Replace(text, "\\s+", " ").Trim() : null;
			}
			catch
			{
				return null;
			}
		}

		private static bool UsableName(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			string text = value.Trim();
			if (!text.StartsWith("|L10N error", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("STRING_", StringComparison.OrdinalIgnoreCase))
			{
				return !text.StartsWith("NAME_", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	internal static class CustomModeHazards
	{
		private static readonly object installGate = new object();

		private static readonly FieldInfo levelObjects = AccessTools.Field(typeof(IVroom), "_levelObjects");

		private static bool installed;

		private static bool clientActive;

		private static float nextClientScan;

		private static readonly Dictionary<TrapLevelObject, bool> hiddenTraps = new Dictionary<TrapLevelObject, bool>();

		internal static bool ClientActive => clientActive;

		internal static void Install(Harmony harmony)
		{
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			lock (installGate)
			{
				if (installed)
				{
					return;
				}
				if (levelObjects == null || levelObjects.FieldType != typeof(Dictionary<int, ILevelObjectInfo>))
				{
					throw new MissingFieldException("Native level-object registration changed.");
				}
				List<KeyValuePair<MethodInfo, MethodInfo>> list = new List<KeyValuePair<MethodInfo, MethodInfo>>();
				try
				{
					Patch(harmony, list, typeof(IVroom), "InitLevel", "AfterInitLevel", postfix: true);
					Patch(harmony, list, typeof(IVroom), "LevelObjectEventInternal", "BeforeTrapEvent", postfix: false);
					Patch(harmony, list, typeof(IVroom), "ExecuteFieldSkillSpawn", "BeforeMapFieldSpawn", postfix: false);
					Patch(harmony, list, typeof(IVroom), "CreateFieldSkillObject", "BeforeFieldFactory", postfix: false);
					Patch(harmony, list, typeof(IVroom), "RunEventActionInternal", "BeforeMapAction", postfix: false);
					Patch(harmony, list, typeof(ItemElement), "CheckSpawnFieldSkill", "BeforeItemHazard", postfix: false);
					Patch(harmony, list, typeof(ItemElement), "CheckSpawnFieldSkillWaitPeriod", "BeforeItemHazard", postfix: false);
					Patch(harmony, list, typeof(TrapLevelObject), "OnAwake", "AfterTrapAwake", postfix: true);
					CustomModeLootLocks.Install(harmony);
					installed = true;
				}
				catch
				{
					foreach (KeyValuePair<MethodInfo, MethodInfo> item in list)
					{
						try
						{
							harmony.Unpatch((MethodBase)item.Key, item.Value);
						}
						catch
						{
						}
					}
					throw;
				}
			}
		}

		private static void Patch(Harmony harmony, List<KeyValuePair<MethodInfo, MethodInfo>> hooks, Type type, string name, string patchName, bool postfix)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(CustomModeHazards), patchName, (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo.IsStatic || methodInfo2 == null)
			{
				throw new MissingMethodException("Native custom-room hazard entry changed: " + type.Name + "." + name);
			}
			hooks.Add(new KeyValuePair<MethodInfo, MethodInfo>(methodInfo, methodInfo2));
			if (postfix)
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void AfterInitLevel(IVroom __instance)
		{
			if (!SurvivalNativeWorld.IsSurvivalRoom(__instance) || !(levelObjects.GetValue(__instance) is Dictionary<int, ILevelObjectInfo> dictionary))
			{
				return;
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, ILevelObjectInfo> item in dictionary)
			{
				if (IsTrap(item.Value))
				{
					list.Add(item.Key);
				}
			}
			foreach (int item2 in list)
			{
				dictionary.Remove(item2);
			}
		}

		private static bool IsTrap(ILevelObjectInfo value)
		{
			if (value != null)
			{
				return value.DataOrigin is TrapLevelObject;
			}
			return false;
		}

		private static bool BeforeTrapEvent(IVroom __instance, ILevelObjectInfo __0, ref MsgErrorCode __result)
		{
			if (!SurvivalNativeWorld.IsSurvivalRoom(__instance) || !IsTrap(__0))
			{
				return true;
			}
			__result = (MsgErrorCode)10000001;
			return false;
		}

		private static bool BeforeMapFieldSpawn(IVroom __instance)
		{
			return !SurvivalNativeWorld.IsSurvivalRoom(__instance);
		}

		private static bool IsPlayerSource(IVroom room, VActor actor)
		{
			VPlayer val = (VPlayer)(object)((actor is VPlayer) ? actor : null);
			if (val != null && ((VActor)val).VRoom == room)
			{
				return ((VActor)val).IsAliveStatus();
			}
			return false;
		}

		private static bool BeforeFieldFactory(IVroom __instance, ISkillContext __4, ref List<FieldSkillObject> __result)
		{
			if (!SurvivalNativeWorld.IsSurvivalRoom(__instance))
			{
				return true;
			}
			if (__4 != null && __4.ContextInfo != null && IsPlayerSource(__instance, (VActor)(object)__4.ContextInfo.Creature))
			{
				return true;
			}
			__result = new List<FieldSkillObject>();
			return false;
		}

		private static bool BeforeItemHazard(IVroom __0, VActor __1)
		{
			if (SurvivalNativeWorld.IsSurvivalRoom(__0))
			{
				return !(__1 is VLootingObject);
			}
			return true;
		}

		private static bool BeforeMapAction(IVroom __instance, IGameAction __0, ref bool __result)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!SurvivalNativeWorld.IsSurvivalRoom(__instance))
			{
				return true;
			}
			bool flag = __0 is GameActionInstantKill || __0 is GameActionAddAbnormal;
			GameActionChangeMutableStat val = (GameActionChangeMutableStat)(object)((__0 is GameActionChangeMutableStat) ? __0 : null);
			if (val != null)
			{
				flag |= IsHarmfulStat(val.StatType, val.Value, val.Value);
			}
			GameActionChangeMutableStatRandom val2 = (GameActionChangeMutableStatRandom)(object)((__0 is GameActionChangeMutableStatRandom) ? __0 : null);
			if (val2 != null)
			{
				flag |= IsHarmfulStat(val2.StatType, val2.MinValue, val2.MaxValue);
			}
			if (!flag)
			{
				return true;
			}
			__result = true;
			return false;
		}

		private static bool IsHarmfulStat(MutableStatType type, long min, long max)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			if ((int)type != 1 || min >= 0)
			{
				if ((int)type == 6)
				{
					return max > 0;
				}
				return false;
			}
			return true;
		}

		internal static bool AllowDamage(IVroom room, ApplyDamageArgs args)
		{
			if (!SurvivalNativeWorld.IsSurvivalRoom(room) || args == null)
			{
				return true;
			}
			VActor victim = args.Victim;
			VPlayer val = (VPlayer)(object)((victim is VPlayer) ? victim : null);
			if (val == null || ((VActor)val).VRoom != room)
			{
				return true;
			}
			if (IsPlayerSource(room, args.Attacker))
			{
				return true;
			}
			VActor attacker = args.Attacker;
			FieldSkillObject val2 = (FieldSkillObject)(object)((attacker is FieldSkillObject) ? attacker : null);
			if (val2 != null && ((VActor)val2).VRoom == room)
			{
				return IsPlayerSource(room, val2.CasterActor);
			}
			return false;
		}

		internal static void UpdateClient(bool active)
		{
			if (!active)
			{
				clientActive = false;
				foreach (KeyValuePair<TrapLevelObject, bool> hiddenTrap in hiddenTraps)
				{
					if ((Object)(object)hiddenTrap.Key != (Object)null && (Object)(object)((Component)hiddenTrap.Key).gameObject != (Object)null)
					{
						((Component)hiddenTrap.Key).gameObject.SetActive(hiddenTrap.Value);
					}
				}
				hiddenTraps.Clear();
				nextClientScan = 0f;
				return;
			}
			bool num = !clientActive;
			clientActive = true;
			if (num || !(Time.unscaledTime < nextClientScan))
			{
				nextClientScan = Time.unscaledTime + 1f;
				TrapLevelObject[] array = Object.FindObjectsOfType<TrapLevelObject>();
				for (int i = 0; i < array.Length; i++)
				{
					HideTrap(array[i]);
				}
			}
		}

		private static void AfterTrapAwake(TrapLevelObject __instance)
		{
			if (clientActive)
			{
				HideTrap(__instance);
			}
		}

		private static void HideTrap(TrapLevelObject trap)
		{
			//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 ((Object)(object)trap == (Object)null || (Object)(object)((Component)trap).gameObject == (Object)null)
			{
				return;
			}
			Scene scene = ((Component)trap).gameObject.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				if (!hiddenTraps.ContainsKey(trap))
				{
					hiddenTraps.Add(trap, ((Component)trap).gameObject.activeSelf);
				}
				((Component)trap).gameObject.SetActive(false);
			}
		}
	}
	internal static class CustomModeLootLocks
	{
		private static readonly object installGate = new object();

		private static bool installed;

		internal static void Install(Harmony harmony)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			lock (installGate)
			{
				if (installed)
				{
					return;
				}
				List<KeyValuePair<MethodInfo, MethodInfo>> list = new List<KeyValuePair<MethodInfo, MethodInfo>>();
				try
				{
					string[] array = new string[3] { "HandleGrapLootingObject", "HandleUnhangItem", "HandleHangItem" };
					foreach (string text in array)
					{
						MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(VPlayer), text, new Type[2]
						{
							typeof(int),
							typeof(int)
						}, (Type[])null);
						MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(CustomModeLootLocks), "BeforePickup", (Type[])null, (Type[])null);
						if (methodInfo == null || methodInfo.IsStatic || methodInfo.ReturnType != typeof(MsgErrorCode))
						{
							throw new MissingMethodException("Native custom-room pickup entry changed: " + text);
						}
						list.Add(new KeyValuePair<MethodInfo, MethodInfo>(methodInfo, methodInfo2));
						harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
					MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(LootingLevelObject), "CanGrap", new Type[1] { typeof(ProtoActor) }, (Type[])null);
					MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(CustomModeLootLocks), "BeforeClientPickup", (Type[])null, (Type[])null);
					if (methodInfo3 == null || methodInfo3.IsStatic || methodInfo3.ReturnType != typeof(bool))
					{
						throw new MissingMethodException("Native loot interaction feedback changed.");
					}
					list.Add(new KeyValuePair<MethodInfo, MethodInfo>(methodInfo3, methodInfo4));
					harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					installed = true;
				}
				catch
				{
					foreach (KeyValuePair<MethodInfo, MethodInfo> item in list)
					{
						try
						{
							harmony.Unpatch((MethodBase)item.Key, item.Value);
						}
						catch
						{
						}
					}
					throw;
				}
			}
		}

		private static bool BeforePickup(VPlayer __instance, ref MsgErrorCode __result)
		{
			if (__instance == null || !SurvivalNativeWorld.IsSurvivalRoom(((VActor)__instance).VRoom))
			{
				return true;
			}
			__result = (MsgErrorCode)20000023;
			return false;
		}

		private static bool BeforeClientPickup(ref bool __result)
		{
			if (!CustomModeHazards.ClientActive)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	public sealed class GamePlayerInfo
	{
		public string Id;

		public string Name;

		public bool Alive;

		public bool IsHost;
	}
	public sealed class GameAdapter
	{
		private sealed class StatOwner
		{
			public string Id;
		}

		private sealed class SaveCreation
		{
			public VWorld World;

			public VRoomManager Manager;

			public int Slot;
		}

		private readonly IGameSink sink;

		private readonly object rosterGate = new object();

		private readonly ConditionalWeakTable<object, StatOwner> statOwners = new ConditionalWeakTable<object, StatOwner>();

		private readonly HashSet<string> diagnostics = new HashSet<string>();

		private readonly HashSet<string> begunRooms = new HashSet<string>();

		private readonly HashSet<string> endedRooms = new HashSet<string>();

		private readonly HashSet<InventoryController> refreshingInventories = new HashSet<InventoryController>();

		private readonly object generationGate = new object();

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

		private readonly object runGate = new object();

		private readonly HashSet<IVroom> retiredRunRooms = new HashSet<IVroom>();

		private readonly HashSet<string> terminatedRoomKeys = new HashSet<string>(StringComparer.Ordinal);

		private SaveCreation pendingSaveCreation;

		private VWorld creationInspectedWorld;

		private VWorld explicitCreationPreviousWorld;

		private int explicitCreationSlot = -1;

		private int newGameRequestSlot = -1;

		private int newGameRequestDepth;

		private readonly object trainGate = new object();

		private GameMainBase loadedTrainMain;

		private GameMainBase loadingUiMain;

		private bool trainMembersLoaded;

		private string trainTransition = "";

		private string notifiedTrainTransition = "";

		private string worldScope = Guid.NewGuid().ToString("N");

		private List<GamePlayerInfo> serverRoster = new List<GamePlayerInfo>();

		private readonly HashSet<VPlayer> initializedPlayers = new HashSet<VPlayer>();

		private VWorld world;

		private bool inputCaptured;

		private bool monsterInputSuppressed;

		private CursorLockMode cursorBeforeOverlay;

		private bool cursorVisibleBeforeOverlay;

		private bool cursorLease;

		private NativeModalCursorLease nativeModalCursor;

		private float nextRoster;

		internal static readonly BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		public static GameAdapter Instance { get; private set; }

		internal bool InputCaptured
		{
			get
			{
				if (!inputCaptured)
				{
					return monsterInputSuppressed;
				}
				return true;
			}
		}

		internal bool UiInputCaptured => inputCaptured;

		public bool IsHost
		{
			get
			{
				if (world != null)
				{
					return world.Running;
				}
				return false;
			}
		}

		public string LocalPlayerId
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					return SteamUser.GetSteamID().m_SteamID.ToString(CultureInfo.InvariantCulture);
				}
				catch
				{
					return "";
				}
			}
		}

		public bool IsInShop
		{
			get
			{
				try
				{
					GameMainBase main = Hub.Main;
					if ((Object)(object)main == (Object)null)
					{
						return false;
					}
					string text = ((object)main).GetType().Name.ToLowerInvariant();
					return text.Contains("maintenance") || text.Contains("maintenence");
				}
				catch
				{
					return false;
				}
			}
		}

		public long Money
		{
			get
			{
				try
				{
					return (!((Object)(object)Hub.Main == (Object)null)) ? Hub.Main.CurrentCurrency : 0;
				}
				catch
				{
					return 0L;
				}
			}
		}

		public bool CanRenderModUi
		{
			get
			{
				try
				{
					GameMainBase main = Hub.Main;
					if ((Object)(object)main == (Object)null || (!(main is InTramWaitingScene) && !(main is GamePlayScene) && !(main is MaintenanceScene) && !(main is DeathMatchScene)))
					{
						return false;
					}
					if ((Object)(object)main == (Object)(object)loadingUiMain || !main.IsGameLogicStarted || main.IsCrashlandingLoading)
					{
						return false;
					}
					if ((bool)Read(main, "EnterExitingProcess") || (bool)Read(main, "goBackToMainMenuFlag") || (bool)Read(main, "_returningToMainMenu"))
					{
						return false;
					}
					UIManager val = (UIManager)(((Object)(object)Hub.s == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
					if ((Object)(object)val == (Object)null)
					{
						return false;
					}
					UIPrefab_Scene_Loading ui_sceneloading = val.ui_sceneloading;
					if ((Object)(object)ui_sceneloading != (Object)null && ((Component)ui_sceneloading).gameObject.activeInHierarchy)
					{
						return false;
					}
					object obj = Read(val, "fadeInImage");
					Image val2 = (Image)((obj is Image) ? obj : null);
					if ((Object)(object)val2 != (Object)null && ((Behaviour)val2).isActiveAndEnabled)
					{
						return false;
					}
					return true;
				}
				catch
				{
					return false;
				}
			}
		}

		public bool CanPresentRewards
		{
			get
			{
				try
				{
					GameMainBase main = Hub.Main;
					InTramWaitingScene val = (InTramWaitingScene)(object)((main is InTramWaitingScene) ? main : null);
					if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)loadedTrainMain || !((GameMainBase)val).IsGameLogicStarted)
					{
						return false;
					}
					if (!(Read(val, "EnteringCompleteAll") is bool) || !(bool)Read(val, "EnteringCompleteAll"))
					{
						return false;
					}
					if (Read(val, "EnterExitingProcess") is bool && (bool)Read(val, "EnterExitingProcess"))
					{
						return false;
					}
					if (Read(val, "goBackToMainMenuFlag") is bool && (bool)Read(val, "goBackToMainMenuFlag"))
					{
						return false;
					}
					if (!IsHost)
					{
						return true;
					}
					lock (trainGate)
					{
						return trainMembersLoaded;
					}
				}
				catch
				{
					return false;
				}
			}
		}

		public string SaveKey
		{
			get
			{
				try
				{
					if (world == null)
					{
						return "";
					}
					string text = LocalPlayerId + "-slot-" + world.SaveSlotID.ToString(CultureInfo.InvariantCulture);
					return text + "-run-" + GetGeneration(text);
				}
				catch
				{
					return "";
				}
			}
		}

		internal void SetMonsterInputSuppressed(bool suppressed)
		{
			monsterInputSuppressed = suppressed;
		}

		public GameAdapter(IGameSink target)
		{
			sink = target;
			Instance = this;
		}

		public void Initialize(Harmony harmony)
		{
			GamePatches.Install(harmony);
			TryFindWorld();
		}

		private void TryFindWorld()
		{
			try
			{
				VWorld val = (VWorld)(((Object)(object)Hub.s == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
				if (val != world)
				{
					RegisterWorld(val);
				}
			}
			catch (Exception ex)
			{
				WarnOnce("world", "Monde serveur indisponible : " + ex.Message);
			}
		}

		public void Update()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			TryFindWorld();
			ReconcileNativeModalCursor();
			if (Time.unscaledTime >= nextRoster)
			{
				nextRoster = Time.unscaledTime + 0.35f;
				if (IsHost)
				{
					VWorld captured = world;
					try
					{
						captured.VRoomManager.Invoke((Command)delegate
						{
							SnapshotServerRoster(captured);
						});
					}
					catch (Exception ex)
					{
						WarnOnce("roster", "Lecture des joueurs indisponible : " + ex.Message);
					}
				}
			}
			NotifyTrainReturnIfReady();
		}

		public List<GamePlayerInfo> GetRoster()
		{
			List<GamePlayerInfo> list = new List<GamePlayerInfo>();
			try
			{
				GameMainBase main = Hub.Main;
				if ((Object)(object)main != (Object)null)
				{
					foreach (ProtoActor allPlayer in main.GetAllPlayers())
					{
						if (!((Object)(object)allPlayer == (Object)null) && allPlayer.steamID != 0L)
						{
							list.Add(new GamePlayerInfo
							{
								Id = allPlayer.steamID.ToString(CultureInfo.InvariantCulture),
								Name = allPlayer.nickName,
								Alive = !allPlayer.dead,
								IsHost = allPlayer.IsHost
							});
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce("client-roster", "Liste des joueurs : " + ex.Message);
			}
			if (list.Count == 0 && IsHost)
			{
				lock (rosterGate)
				{
					list = new List<GamePlayerInfo>(serverRoster);
				}
			}
			return (from p in list
				group p by p.Id into g
				select g.First()).ToList();
		}

		private static IEnumerable<IVroom> Rooms(VWorld current)
		{
			IDictionary dictionary = ((current == null) ? null : (Read(current.VRoomManager, "_vrooms") as IDictionary));
			if (dictionary == null)
			{
				yield break;
			}
			foreach (DictionaryEntry item in dictionary)
			{
				object? value = item.Value;
				IVroom val = (IVroom)((value is IVroom) ? value : null);
				if (val != null)
				{
					yield return val;
				}
			}
		}

		private void SnapshotServerRoster(VWorld captured)
		{
			if (captured == null || captured != world)
			{
				return;
			}
			List<GamePlayerInfo> list = new List<GamePlayerInfo>();
			foreach (IVroom item in Rooms(captured))
			{
				item.IterateAllPlayer((Action<VPlayer>)delegate(VPlayer p)
				{
					//IL_002e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0034: Invalid comparison between Unknown and I4
					if (p.SteamID != 0L)
					{
						list.Add(new GamePlayerInfo
						{
							Id = Id(p),
							Name = ((VActor)p).ActorName,
							Alive = ((int)((VCreature)p).LifeCycle == 1 && !p.Wasted),
							IsHost = p.IsHost
						});
						bool flag2;
						lock (rosterGate)
						{
							flag2 = !initializedPlayers.Contains(p);
						}
						if (flag2 && RefreshPlayer(p))
						{
							lock (rosterGate)
							{
								initializedPlayers.Add(p);
							}
						}
					}
				});
			}
			lock (rosterGate)
			{
				serverRoster = (from p in list
					group p by p.Id into g
					select g.First()).ToList();
			}
			bool flag = false;
			foreach (IVroom item2 in Rooms(captured))
			{
				VWaitingRoom val = (VWaitingRoom)(object)((item2 is VWaitingRoom) ? item2 : null);
				if (val != null)
				{
					flag = true;
					TrainMembersEntered(val);
				}
			}
			if (flag)
			{
				return;
			}
			lock (trainGate)
			{
				trainMembersLoaded = false;
			}
		}

		public void ApplyAllStats()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			VWorld captured = world;
			if (captured == null || !captured.Running)
			{
				return;
			}
			try
			{
				captured.VRoomManager.Invoke((Command)delegate
				{
					if (captured != world)
					{
						return;
					}
					foreach (IVroom item in Rooms(captured))
					{
						item.IterateAllPlayer((Action<VPlayer>)delegate(VPlayer player)
						{
							RefreshPlayer(player);
						});
					}
				});
			}
			catch (Exception ex)
			{
				WarnOnce("apply-stats", "Application des statistiques : " + ex.Message);
			}
		}

		private bool RefreshPlayer(VPlayer player)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Invalid comparison between Unknown and I4
			try
			{
				StatController statControlUnit = ((VActor)player).StatControlUnit;
				if (statControlUnit == null || ((VActor)player).InventoryControlUnit == null || Read(((VActor)player).InventoryControlUnit, "_inventorySlots") == null)
				{
					return false;
				}
				object obj = Read(statControlUnit, "StatManager");
				RegisterStatManager(obj);
				object obj2 = Read(obj, "_totalStats");
				CommonStats val = (CommonStats)((obj2 is CommonStats) ? obj2 : null);
				if (val != null)
				{
					val.AlteredStatTypes.Add((StatType)1);
					val.AlteredStatTypes.Add((StatType)7);
					val.AlteredStatTypes.Add((StatType)4);
					val.AlteredStatTypes.Add((StatType)5);
					RefreshRadiationMaximum(obj, val);
				}
				if ((int)((VCreature)player).LifeCycle == 1)
				{
					long num = Math.Min(statControlUnit.GetCurrentHP(), statControlUnit.GetSpecificStatValue((StatType)1));
					long num2 = Math.Min(statControlUnit.GetCurrentStamina(), statControlUnit.GetSpecificStatValue((StatType)7));
					Call(obj, "SetMutableStat", (object)(MutableStatType)1, num, null, null);
					Call(obj, "SetMutableStat", (object)(MutableStatType)7, num2, null, null);
				}
				statControlUnit.SyncChangedImmutableStats();
				RefreshRadiationCurrent(obj, player);
				InventoryChanged(((VActor)player).InventoryControlUnit);
				((VActor)player).InventoryControlUnit.OnChangeInventory();
				return true;
			}
			catch (Exception ex)
			{
				WarnOnce("refresh-player", "Mise à jour d'un joueur : " + ex.Message);
				return false;
			}
		}

		public void TrySpend(string playerId, int amount, Action<bool> completed)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			VWorld captured = world;
			if (amount <= 0 || captured == null || !captured.Running)
			{
				completed(obj: false);
				return;
			}
			try
			{
				captured.VRoomManager.Invoke((Command)delegate
				{
					//IL_008d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0093: Invalid comparison between Unknown and I4
					if (captured != world || !captured.Running)
					{
						completed(obj: false);
					}
					else
					{
						bool obj2 = false;
						try
						{
							foreach (IVroom item in Rooms(captured))
							{
								MaintenanceRoom val = (MaintenanceRoom)(object)((item is MaintenanceRoom) ? item : null);
								if (val != null && !((IVroom)val).IsSessionEnding)
								{
									VPlayer buyer = null;
									((IVroom)val).IterateAllPlayer((Action<VPlayer>)delegate(VPlayer p)
									{
										if (Id(p) == playerId)
										{
											buyer = p;
										}
									});
									if (buyer != null && (int)((VCreature)buyer).LifeCycle == 1 && !buyer.Wasted && ((IVroom)val).Currency >= amount)
									{
										val.AddCurrency(-amount);
										obj2 = true;
										break;
									}
								}
							}
						}
						catch (Exception ex)
						{
							WarnOnce("spend", "Achat refusé : " + ex.Message);
						}
						completed(obj2);
					}
				});
			}
			catch
			{
				completed(obj: false);
			}
		}

		public void SetInputCaptured(bool captured)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (captured == inputCaptured)
			{
				if (captured)
				{
					EnforceInputCapture();
				}
				return;
			}
			if (captured)
			{
				cursorBeforeOverlay = Cursor.lockState;
				cursorVisibleBeforeOverlay = Cursor.visible;
				cursorLease = true;
				inputCaptured = true;
				EnforceInputCapture();
				return;
			}
			inputCaptured = false;
			if (cursorLease)
			{
				cursorLease = false;
				Cursor.lockState = cursorBeforeOverlay;
				Cursor.visible = cursorVisibleBeforeOverlay;
			}
		}

		public void EnforceInputCapture()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (inputCaptured)
			{
				if ((int)Cursor.lockState != 0)
				{
					Cursor.lockState = (CursorLockMode)0;
				}
				if (!Cursor.visible)
				{
					Cursor.visible = true;
				}
			}
		}

		internal void NativeInputCaptureRequested(bool captured)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (inputCaptured && cursorLease)
			{
				cursorBeforeOverlay = (CursorLockMode)(captured ? 1 : 0);
				cursorVisibleBeforeOverlay = !captured && Cursor.visible;
			}
		}

		internal void NativeModalCaptureRequested(bool captured)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (nativeModalCursor == null)
			{
				nativeModalCursor = new NativeModalCursorLease();
			}
			nativeModalCursor.ObserveNativeCapture(captured, Hub.Main, (inputCaptured && cursorLease) ? cursorBeforeOverlay : Cursor.lockState, (inputCaptured && cursorLease) ? cursorVisibleBeforeOverlay : Cursor.visible);
		}

		internal void ReconcileNativeModalCursor()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (nativeModalCursor == null)
			{
				nativeModalCursor = new NativeModalCursorLease();
			}
			bool modal;
			bool flag = NativeModalCursorLease.TryReadNativeModal(out modal);
			if (nativeModalCursor.Reconcile(Hub.Main, flag && CanRenderModUi, Application.isFocused, modal, out var mode, out var shown))
			{
				if (inputCaptured && cursorLease)
				{
					cursorBeforeOverlay = mode;
					cursorVisibleBeforeOverlay = shown;
				}
				else
				{
					NativeModalCursorLease.Apply(mode, shown);
				}
			}
			if (inputCaptured)
			{
				EnforceInputCapture();
			}
		}

		public unsafe static bool UiKeyDown(KeyCode key)
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Keyboard current = Keyboard.current;
				if (current != null)
				{
					string text = ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
					if (text == "Return")
					{
						text = "Enter";
					}
					else if (text == "KeypadEnter")
					{
						text = "NumpadEnter";
					}
					else if (text.StartsWith("Alpha", StringComparison.Ordinal))
					{
						text = "Digit" + text.Substring(5);
					}
					else if (text.StartsWith("Keypad", StringComparison.Ordinal))
					{
						text = "Numpad" + text.Substring(6);
					}
					else if (text == "LeftControl")
					{
						text = "LeftCtrl";
					}
					else if (text == "RightControl")
					{
						text = "RightCtrl";
					}
					if (Enum.TryParse<Key>(text, ignoreCase: true, out Key result) && (int)result != 0)
					{
						return ((ButtonControl)current[result]).wasPressedThisFrame;
					}
				}
			}
			catch
			{
			}
			try
			{
				return Input.GetKeyDown(key);
			}
			catch
			{
				return false;
			}
		}

		internal void RegisterWorld(VWorld value)
		{
			lock (runGate)
			{
				if (world != value)
				{
					retiredRunRooms.Clear();
					terminatedRoomKeys.Clear();
					lock (begunRooms)
					{
						begunRooms.Clear();
						endedRooms.Clear();
					}
					lock (rosterGate)
					{
						serverRoster.Clear();
						initializedPlayers.Clear();
					}
					worldScope = Guid.NewGuid().ToString("N");
					lock (trainGate)
					{
						trainMembersLoaded = false;
						trainTransition = "";
						notifiedTrainTransition = "";
					}
				}
				world = value;
			}
		}

		private static string GenerationPath(string slot)
		{
			return Path.Combine(MelonEnvironment.UserDataDirectory, "MimesisPowerUps", "Runs", slot + ".run");
		}

		private string GetGeneration(string slot)
		{
			lock (generationGate)
			{
				if (generations.TryGetValue(slot, out var value))
				{
					return value;
				}
				value = "legacy";
				string path = GenerationPath(slot);
				if (File.Exists(path))
				{
					string text = File.ReadAllText(path).Trim();
					if (Guid.TryParseExact(text, "N", out var _))
					{
						value = text;
					}
				}
				generations[slot] = value;
				return value;
			}
		}

		internal void NewGameCreated(int slotID)
		{
			RotateGeneration(slotID);
		}

		internal void NewGameRequested(int slotID)
		{
			lock (runGate)
			{
				newGameRequestDepth++;
				newGameRequestSlot = slotID;
			}
		}

		internal void NewGameRequestEnded()
		{
			lock (runGate)
			{
				if (newGameRequestDepth > 0)
				{
					newGameRequestDepth--;
				}
				if (newGameRequestDepth == 0)
				{
					newGameRequestSlot = -1;
				}
			}
		}

		private static VWorld CurrentNativeWorld()
		{
			if (!((Object)(object)Hub.s == (Object)null))
			{
				object obj = Read(Hub.s, "vworld");
				return (VWorld)((obj is VWorld) ? obj : null);
			}
			return null;
		}

		internal void MenuRoomCreating()
		{
			lock (runGate)
			{
				explicitCreationSlot = ((newGameRequestDepth > 0) ? newGameRequestSlot : (-1));
				explicitCreationPreviousWorld = CurrentNativeWorld();
			}
		}

		internal void MaintenanceStarting(VRoomManager manager, int slotID, bool loadFromAutoSave)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			try
			{
				lock (runGate)
				{
					VWorld val = CurrentNativeWorld();
					if (val == null || manager != val.VRoomManager || slotID != val.SaveSlotID || val == creationInspectedWorld)
					{
						return;
					}
					creationInspectedWorld = val;
					pendingSaveCreation = null;
					object obj = Read(manager, "_gameSessionInfo");
					GameSessionInfo val2 = (GameSessionInfo)((obj is GameSessionInfo) ? obj : null);
					if (!(val2 == null || (int)val2.GameSessionState != 1 || loadFromAutoSave) && MMSaveGameData.CheckSaveSlotID(slotID, false))
					{
						PlatformMgr instance = MonoSingleton<PlatformMgr>.Instance;
						if (!((Object)(object)instance == (Object)null) && ((explicitCreationSlot == slotID && explicitCreationPreviousWorld != val) || !instance.IsSaveFileExist(MMSaveGameData.GetSaveFileName(slotID, false))))
						{
							pendingSaveCreation = new SaveCreation
							{
								World = val,
								Manager = manager,
								Slot = slotID
							};
							explicitCreationSlot = -1;
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce("new-save-probe", "Détection de la nouvelle sauvegarde : " + ex.Message);
			}
		}

		internal void MaintenanceSaved(MaintenanceRoom room, int slotID, bool autoSave, MsgErrorCode result)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (room == null || autoSave || (int)result != 0)
			{
				return;
			}
			try
			{
				lock (runGate)
				{
					SaveCreation saveCreation = pendingSaveCreation;
					VWorld val = CurrentNativeWorld();
					if (saveCreation != null && val == saveCreation.World && val.Running && slotID == saveCreation.Slot && slotID == val.SaveSlotID && ((IVroom)room).RoomManager == saveCreation.Manager && val.VRoomManager == saveCreation.Manager)
					{
						PlatformMgr instance = MonoSingleton<PlatformMgr>.Instance;
						if (!((Object)(object)instance == (Object)null) && instance.IsSaveFileExist(MMSaveGameData.GetSaveFileName(slotID, false)) && RotateGeneration(slotID))
						{
							pendingSaveCreation = null;
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce("new-save-commit", "Identification de la nouvelle sauvegarde : " + ex.Message);
			}
		}

		internal void NativeSaveLoaded(GameSessionInfo info)
		{
			lock (runGate)
			{
				if (pendingSaveCreation != null && info != null && Read(pendingSaveCreation.Manager, "_gameSessionInfo") == info)
				{
					pendingSaveCreation = null;
				}
			}
		}

		private bool RotateGeneration(int slotID)
		{
			string localPlayerId = LocalPlayerId;
			if (string.IsNullOrEmpty(localPlayerId))
			{
				return false;
			}
			string text = localPlayerId + "-slot-" + slotID.ToString(CultureInfo.InvariantCulture);
			string text2 = Guid.NewGuid().ToString("N");
			lock (generationGate)
			{
				generations[text] = text2;
				try
				{
					string text3 = GenerationPath(text);
					Directory.CreateDirectory(Path.GetDirectoryName(text3));
					string text4 = text3 + ".tmp";
					File.WriteAllText(text4, text2);
					if (File.Exists(text3))
					{
						File.Replace(text4, text3, null);
					}
					else
					{
						File.Move(text4, text3);
					}
				}
				catch (Exception ex)
				{
					WarnOnce("new-save-generation", "Identification de la nouvelle partie : " + ex.Message);
				}
			}
			return true;
		}

		internal void RunTerminated(VRoomManager manager, RoomDrainInfo drain)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			if (SurvivalNativeWorld.SuppressNormalRunResults)
			{
				return;
			}
			lock (runGate)
			{
				VWorld val = world;
				if (val == null || !val.Running || manager != val.VRoomManager || drain == null || drain.RoomID <= 0)
				{
					return;
				}
				object obj = Read(manager, "_gameSessionInfo");
				GameSessionInfo val2 = (GameSessionInfo)((obj is GameSessionInfo) ? obj : null);
				if (val2 == null || (int)val2.GameSessionState != 7)
				{
					return;
				}
				IVroom val3 = Rooms(val).FirstOrDefault((Func<IVroom, bool>)((IVroom r) => r.RoomID == drain.RoomID));
				if (!(val3 is DeathMatchRoom) || retiredRunRooms.Contains(val3))
				{
					return;
				}
				string item = val2.CurrentSessionID.ToString(CultureInfo.InvariantCulture) + ":" + drain.RoomID.ToString(CultureInfo.InvariantCulture);
				if (terminatedRoomKeys.Contains(item) || !RotateGeneration(val.SaveSlotID))
				{
					return;
				}
				pendingSaveCreation = null;
				terminatedRoomKeys.Add(item);
				foreach (IVroom item2 in Rooms(val))
				{
					if (item2 is DungeonRoom || item2 is DeathMatchRoom)
					{
						retiredRunRooms.Add(item2);
					}
				}
				lock (begunRooms)
				{
					begunRooms.Clear();
					endedRooms.Clear();
				}
				worldScope = Guid.NewGuid().ToString("N");
				lock (rosterGate)
				{
					initializedPlayers.Clear();
				}
				lock (trainGate)
				{
					trainMembersLoaded = false;
					trainTransition = "";
					notifiedTrainTransition = "";
				}
			}
		}

		internal void RegisterStatManager(object manager)
		{
			if (manager == null)
			{
				return;
			}
			object obj = Read(manager, "_self");
			VPlayer val = (VPlayer)((obj is VPlayer) ? obj : null);
			object obj2 = Read(manager, "_totalStats");
			if (val == null || obj2 == null)
			{
				return;
			}
			string id;
			try
			{
				if (val.SteamID == 0L)
				{
					return;
				}
				id = Id(val);
			}
			catch
			{
				return;
			}
			statOwners.GetValue(obj2, (object key) => new StatOwner()).Id = id;
		}

		internal long ScaleStat(object totals, StatType type, long original)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			if (!statOwners.TryGetValue(totals, out var value))
			{
				return original;
			}
			Stat stat;
			if ((int)type == 1)
			{
				stat = Stat.Health;
			}
			else if ((int)type == 7)
			{
				stat = Stat.Stamina;
			}
			else
			{
				if ((int)type != 4 && (int)type != 5)
				{
					return original;
				}
				stat = Stat.Speed;
			}
			return Scale(original, Stats(value.Id).Get(stat));
		}

		internal float ScaleStrength(object growth, float original)
		{
			object obj = Read(growth, "_self");
			VPlayer val = (VPlayer)((obj is VPlayer) ? obj : null);
			if (val != null)
			{
				return original * (float)(Stats(Id(val)).Strength / 100.0);
			}
			return original;
		}

		internal long ScaleWeight(object growth, long original)
		{
			object obj = Read(growth, "_self");
			VPlayer val = (VPlayer)((obj is VPlayer) ? obj : null);
			if (val != null)
			{
				return Scale(original, Stats(Id(val)).Strength);
			}
			return original;
		}

		private static long Scale(long original, double percent)
		{
			if (original <= 0)
			{
				return original;
			}
			double num = (double)original * percent / 100.0;
			return Math.Max(1L, (num >= 9.223372036854776E+18) ? long.MaxValue : ((long)Math.Round(num, MidpointRounding.AwayFromZero)));
		}

		private StatBlock Stats(string id)
		{
			return sink.GetStats(id) ?? new StatBlock();
		}

		internal long ScaleRadiationMaximum(object context, long original)
		{
			try
			{
				object obj = Read((context is StatController) ? Read(context, "StatManager") : context, "_self");
				VPlayer val = (VPlayer)((obj is VPlayer) ? obj : null);
				if (val == null || val.SteamID == 0L)
				{
					return original;
				}
				double radiationCapacity = Stats(Id(val)).RadiationCapacity;
				if (double.IsNaN(radiationCapacity) || double.IsInfinity(radiationCapacity))
				{
					return original;
				}
				return Scale(original, Math.Max(50.0, Math.Min(150.0, radiationCapacity)));
			}
			catch
			{
				return original;
			}
		}

		private void RefreshRadiationMaximum(object manager, CommonStats totals)
		{
			DataManager val = (DataManager)(((Object)(object)Hub.s == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if (totals != null && !((Object)(object)val == (Object)null) && val.ExcelDataManager != null && totals.elements.TryGetValue((StatType)6, out var value) && value != null)
			{
				long c_MaxContaValue = val.ExcelDataManager.Consts.C_MaxContaValue;
				value.Set(ScaleRadiationMaximum(manager, c_MaxContaValue));
				totals.AlteredStatTypes.Add((StatType)6);
			}
		}

		private void RefreshRadiationCurrent(object manager, VPlayer player)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			StatsElement val = (StatsElement)((!(Read(manager, "_mutableStats") is IDictionary dictionary)) ? null : /*isinst with value type is only supported in some contexts*/);
			if (val != null)
			{
				val.Sync(true);
				if ((int)((VCreature)player).LifeCycle == 1)
				{
					Call(manager, "OnChangeMutableStatValue", (object)(MutableStatType)6, val.Value, val.Value, null, null);
				}
				Call(manager, "SyncMutableStats");
			}
		}

		internal static string Id(VPlayer player)
		{
			return player.SteamID.ToString(CultureInfo.InvariantCulture);
		}

		private bool OwnsRoom(IVroom room)
		{
			VWorld val = world;
			lock (runGate)
			{
				return room != null && !SurvivalNativeWorld.IsSurvivalRoom(room) && val != null && val.Running && room.RoomManager == val.VRoomManager && !retiredRunRooms.Contains(room);
			}
		}

		internal void Hit(ApplyDamageArgs args)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			lock (runGate)
			{
				if (args != null && args.Damage > 0)
				{
					VActor victim = args.Victim;
					VMonster val = (VMonster)(object)((victim is VMonster) ? victim : null);
					VActor attacker = args.Attacker;
					VPlayer val2 = (VPlayer)(object)((attacker is VPlayer) ? attacker : null);
					if (val != null && val2 != null && val2.SteamID != 0L && !((VCreature)val).HarmBlocked && (int)((VCreature)val).LifeCycle == 1 && ((VActor)val).VRoom is DungeonRoom && OwnsRoom(((VActor)val).VRoom))
					{
						sink.OnHit(MonsterKey(val), ((VActor)val).MasterID, Id(val2));
					}
				}
			}
		}

		internal void MonsterDeath(VMonster monster, ActorDyingSig sig)
		{
			lock (runGate)
			{
				if (((VActor)monster).VRoom is DungeonRoom && OwnsRoom(((VActor)monster).VRoom))
				{
					VPlayer val = ((sig == null) ? null : ((VActor)monster).VRoom.FindPlayerByObjectID(sig.attackerActorID));
					sink.OnMonsterDeath(MonsterKey(monster), ((VActor)monster).MasterID, (val == null) ? null : Id(val));
				}
			}
		}

		internal void PlayerDeath(VPlayer player)
		{
			lock (runGate)
			{
				if (player.SteamID != 0L && ((VActor)player).VRoom is DungeonRoom && OwnsRoom(((VActor)player).VRoom))
				{
					sink.OnPlayerDeath(Id(player));
				}
			}
		}

		private string RoomKey(IVroom room)
		{
			string text = worldScope;
			long roomID = room.RoomID;
			return text + ":" + roomID.ToString(CultureInfo.InvariantCulture);
		}

		private string MonsterKey(VMonster monster)
		{
			return RoomKey(((VActor)monster).VRoom) + ":" + ((VActor)monster).ObjectID.ToString(CultureInfo.InvariantCulture);
		}

		internal void RoomInitialized(DungeonRoom room, bool success)
		{
			lock (runGate)
			{
				if (!success || !OwnsRoom((IVroom)(object)room))
				{
					return;
				}
				lock (trainGate)
				{
					trainMembersLoaded = false;
				}
				string text = RoomKey((IVroom)(object)room);
				lock (begunRooms)
				{
					if (!begunRooms.Add(text))
					{
						return;
					}
				}
				object instance = Read(room, "_dungeonMasterInfo");
				int num = Convert.ToInt32(Read(instance, "HazardLevel"), CultureInfo.InvariantCulture);
				int num2 = Convert.ToInt32(Read(instance, "RewardLevel"), CultureInfo.InvariantCulture);
				string text2 = Convert.ToString(Read(instance, "mapName"), CultureInfo.InvariantCulture) ?? "";
				bool special = num == 0 && num2 == 0 && text2.IndexOf("JACKPOT", StringComparison.OrdinalIgnoreCase) >= 0;
				sink.OnExpeditionBegin(text, num, num2, special);
			}
		}

		internal void RoomEnding(DungeonRoom room, DungeonState next)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			lock (runGate)
			{
				if (((int)next != 2 && (int)next != 3) || !OwnsRoom((IVroom)(object)room))
				{
					return;
				}
				string text = RoomKey((IVroom)(object)room);
				lock (begunRooms)
				{
					if (!endedRooms.Add(text))
					{
						return;
					}
				}
				string[] aliveIds = (from p in ((IVroom)room).GetAlivePlayers()
					where !p.Wasted && p.SteamID != 0
					select p).Select(Id).Distinct().ToArray();
				sink.OnExpeditionEnd(text, aliveIds);
			}
		}

		internal void SceneLoading(GameMainBase main)
		{
			loadingUiMain = main;
			if ((Object)(object)main == (Object)(object)loadedTrainMain)
			{
				loadedTrainMain = null;
			}
		}

		internal void SceneLoadingEnded(GameMainBase main)
		{
			if ((Object)(object)main == (Object)(object)loadingUiMain)
			{
				loadingUiMain = null;
			}
			if (main is InTramWaitingScene)
			{
				loadedTrainMain = main;
			}
		}

		internal void TrainMembersEntered(VWaitingRoom room)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			lock (runGate)
			{
				if (!OwnsRoom((IVroom)(object)room))
				{
					return;
				}
				bool flag = false;
				try
				{
					int roomTypeMemberCount = world.GetRoomTypeMemberCount(((IVroom)room).Property.vRoomType);
					HashSet<ulong> loaded = Read(room, "_levelLoadCompleteActorIDs") as HashSet<ulong>;
					object obj = Read(room, "_startNotified");
					List<KeyValuePair<ulong, bool>> members = new List<KeyValuePair<ulong, bool>>();
					((IVroom)room).IterateAllPlayer((Action<VPlayer>)delegate(VPlayer player)
					{
						//IL_0016: Unknown result type (might be due to invalid IL or missing references)
						//IL_001c: Invalid comparison between Unknown and I4
						if (player.SteamID != 0L)
						{
							members.Add(new KeyValuePair<ulong, bool>(player.SteamID, (int)((VCreature)player).LifeCycle == 1 && !player.Wasted));
						}
					});
					flag = TrainReturnReadiness.AreAllMembersReady(roomTypeMemberCount, loaded, members, obj is bool && (bool)obj, ((IVroom)room).IsSessionEnding);
				}
				catch (Exception ex)
				{
					WarnOnce("train-members", "Retour au train en attente : " + ex.Message);
				}
				string text = RoomKey((IVroom)(object)room) + ":" + ((IVroom)room).CurrentStage.ToString(CultureInfo.InvariantCulture) + ":" + ((IVroom)room).CurrentCycle.ToString(CultureInfo.InvariantCulture);
				lock (trainGate)
				{
					trainMembersLoaded = flag;
					trainTransition = text;
				}
			}
		}

		private void NotifyTrainReturnIfReady()
		{
			lock (runGate)
			{
				if (!IsHost || !CanPresentRewards)
				{
					return;
				}
				string transitionId;
				lock (trainGate)
				{
					if (!trainMembersLoaded || string.IsNullOrEmpty(trainTransition) || trainTransition == notifiedTrainTransition)
					{
						return;
					}
					transitionId = (notifiedTrainTransition = trainTransition);
				}
				sink.OnTrainReturnReady(transitionId);
			}
		}

		internal bool CanDepartTrain(VWaitingRoom room)
		{
			if (!OwnsRoom((IVroom)(object)room))
			{
				return true;
			}
			try
			{
				return sink.CanDepartTrain();
			}
			catch (Exception ex)
			{
				WarnOnce("train-departure", "Départ du train en attente : " + ex.Message);
				return false;
			}
		}

		internal bool CanUseDepartureLever(ProtoActor actor)
		{
			if ((Object)(object)actor == (Object)null || !actor.AmIAvatar() || !(Hub.Main is InTramWaitingScene))
			{
				return true;
			}
			try
			{
				return sink.CanDepartTrain();
			}
			catch (Exception ex)
			{
				WarnOnce("train-lever", "Levier du train en attente : " + ex.Message);
				return false;
			}
		}

		internal bool CanChangeDepartureLever(IVroom room, ILevelObjectInfo levelObject, int nextState)
		{
			VWaitingRoom val = (VWaitingRoom)(object)((room is VWaitingRoom) ? room : null);
			if (val == null || levelObject == null || !(levelObject.DataOrigin is NewTramLeverLevelObject) || (nextState != 1 && nextState != 2))
			{
				return true;
			}
			return CanDepartTrain(val);
		}

		internal int AdjustSlotKind(int original, InventoryController inventory, int slot)
		{
			object obj = Read(inventory, "_self");
			VPlayer val = (VPlayer)((obj is VPlayer) ? obj : null);
			if (val == null || slot <= 0 || slot == 5 || slot == 6)
			{
				return original;
			}
			int num = ((slot <= 4) ? slot : (slot - 2));
			if (Read(inventory, "_inventorySlots") is IDictionary dictionary && dictionary.Contains(slot) && dictionary[slot] != null)
			{
				return 0;
			}
			if (num <= Stats(Id(val)).ItemCapacity)
			{
				return 0;
			}
			return 3;
		}

		internal bool IsInventorySlotBlocked(InventoryController inventory, int slot)
		{
			return AdjustSlotKind(0, inventory, slot) == 3;
		}

		internal int NativeGenericSlotCount(InventoryController inventory)
		{
			object obj = Read(inventory, "_self");
			VPlayer val = (VPlayer)((obj is VPlayer) ? obj : null);
			if (val == null)
			{
				return 4;
			}
			bool flag = Read(inventory, "_inventorySlots") is IDictionary dictionary && dictionary.Contains(7) && dictionary[7] != null;
			if (!(Stats(Id(val)).ItemCapacity >= 5 || flag))
			{
				return 4;
			}
			return 5;
		}

		internal bool IsSlotHidden(ProtoActor actor, int slot)
		{
			if ((Object)(object)actor == (Object)null || actor.steamID == 0L || slot < 0)
			{
				return false;
			}
			int num = slot + 1;
			if (num == 5 || num == 6)
			{
				return false;
			}
			if (Read(Read(actor, "inventory"), "slotItems") is IList list && slot < list.Count && list[slot] != null)
			{
				return false;
			}
			return ((num <= 4) ? num : (num - 2)) > Stats(actor.steamID.ToString(CultureInfo.InvariantCulture)).ItemCapacity;
		}

		private void RefreshInventory(InventoryController inventory)
		{
			if (inventory == null)
			{
				return;
			}
			object obj = Read(inventory, "_self");
			VPlayer val = (VPlayer)((obj is VPlayer) ? obj : null);
			IDictionary dictionary = Read(inventory, "_inventorySlots") as IDictionary;
			if (val == null || dictionary == null)
			{
				return;
			}
			int itemCapacity = Stats(Id(val)).ItemCapacity;
			if (itemCapacity >= 5 && !dictionary.Contains(7))
			{
				dictionary.Add(7, null);
			}
			object[] array = dictionary.Keys.Cast<object>().ToArray();
			foreach (object obj2 in array)
			{
				int num = Convert.ToInt32(obj2, CultureInfo.InvariantCulture);
				if (num > 0 && num != 5 && num != 6)
				{
					int num2 = ((num <= 4) ? num : (num - 2));
					object? obj3 = dictionary[obj2];
					ItemElement val2 = (ItemElement)((obj3 is ItemElement) ? obj3 : null);
					if (num2 > itemCapacity && val2 != null && TryDropOverflow(inventory, val, val2))
					{
						dictionary[obj2] = null;
					}
				}
			}
			Call(inventory, "SendUpdateInven");
		}

		private bool TryDropOverflow(InventoryController inventory, VPlayer player, ItemElement item)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (item.ReserveDestroy || ((VActor)player).VRoom == null)
			{
				return false;
			}
			try
			{
				((VActor)player).VRoom.CommunicationChannelController.CancelByItem(item.ItemID, (ReasonOfCommunicationChannelCancel)2);
				Call(inventory, "TurnOffItemElement", item);
				Call(inventory, "OnTurnOffItem", item);
				Vector3 val = ((VActor)player).PositionVector;
				if (world != null)
				{
					Vector3 val2 = world.FindNearestPoly(val, 1f);
					if (!float.IsNaN(val2.x) && !float.IsInfinity(val2.x) && Vector3.Distance(val2, val) < 2f)
					{
						val = val2;
					}
				}
				item.SetParent((InventoryController)null);
				PosWithRot val3 = new PosWithRot
				{
					pos = val,
					rot = Vector3.zero
				};
				if (((VActor)player).VRoom.SpawnLootingObject(item, val3, ((VActor)player).IsIndoor, (ReasonOfSpawn)2, 0, 0, 0L, false, false) != 0)
				{
					return true;
				}
				item.SetParent(inventory);
				WarnOnce("overflow-drop", "Objet conservé dans son emplacement : dépôt au sol impossible.");
				return false;
			}
			catch
			{
				item.SetParent(inventory);
				throw;
			}
		}

		internal void InventoryChanged(InventoryController inventory)
		{
			object obj = Read(inventory, "_isRecalculatingSlots");
			if (obj is bool && (bool)obj)
			{
				return;
			}
			lock (refreshingInventories)
			{
				if (!refreshingInventories.Add(inventory))
				{
					return;
				}
			}
			try
			{
				RefreshInventory(inventory);
			}
			catch (Exception ex)
			{
				WarnOnce("inventory-capacity", "Capacité d'inventaire : " + ex.Message);
			}
			finally
			{
				lock (refreshingInventories)
				{
					refreshingInventories.Remove(inventory);
				}
			}
		}

		internal static object Read(object instance, string name)
		{
			if (instance == null)
			{
				return null;
			}
			Type type = instance.GetType();
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if (fieldInfo != null)
			{
				return fieldInfo.GetValue(instance);
			}
			PropertyInfo propertyInfo = AccessTools.Property(type, name);
			if (!(propertyInfo == null))
			{
				return propertyInfo.GetValue(instance, null);
			}
			return null;
		}

		internal static void Write(object instance, string name, object value)
		{
			FieldInfo fieldInfo = ((instance == null) ? null : AccessTools.Field(instance.GetType(), name));
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(instance, value);
			}
		}

		internal static object Call(object instance, string name, params object[] args)
		{
			if (instance == null)
			{
				return null;
			}
			MethodInfo? methodInfo = instance.GetType().GetMethods(All).FirstOrDefault((MethodInfo m) => m.Name == name && m.GetParameters().Length == args.Length);
			if (methodInfo == null)
			{
				throw new MissingMethodException(instance.GetType().FullName, name);
			}
			return methodInfo.Invoke(instance, args);
		}

		internal void WarnOnce(string key, string message)
		{
			lock (diagnostics)
			{
				if (!diagnostics.Add(key))
				{
					return;
				}
			}
			MelonLogger.Warning("Power-Ups : " + message);
		}
	}
	internal static class GamePatches
	{
		private static int installed;

		private static GameAdapter Adapter => GameAdapter.Instance;

		internal static void Install(Harmony harmony)
		{
			Patch(harmony, typeof(VWorld), "Initialize", null, "WorldInitialized");
			InstallSaveCreationHooks(harmony);
			try
			{
				MonsterAudioPerspective.Install(harmony);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Power-Ups : perspective audio du monstre indisponible : " + ex.Message);
			}
			try
			{
				MonsterSoundCleanup.Install(harmony, delegate(string text)
				{
					MelonLogger.Warning(text);
				});
			}
			catch (Exception ex2)
			{
				MelonLogger.Error("Power-Ups : nettoyage audio du monstre indisponible : " + ex2.Message);
			}
			try
			{
				ShopDiscount.Install(harmony);
			}
			catch (Exception ex3)
			{
				MelonLogger.Error("Power-Ups : réduction de la boutique indisponible : " + ex3.Message);
			}
			Patch(harmony, typeof(StatManager), "LoadAllStat", "StatsLoading", "StatsLoaded");
			Patch(harmony, typeof(CommonStats), "GetStatValue", null, "ReadStat");
			string[] array = new string[5] { "IsContaExceeded", "ValidateAndClampMutableStat", "SyncMutableStats", "CalcImmutableStats", "InitMutableStats" };
			foreach (string method in array)
			{
				Patch(harmony, typeof(StatManager), method, null, null, "RadiationMaximumTranspiler");
			}
			Patch(harmony, typeof(StatController), "AdjustConta", null, null, "RadiationMaximumTranspiler");
			Patch(harmony, typeof(IVroom), "RecoverAllMemberConta", null, null, "RadiationRecoveryTranspiler");
			Patch(harmony, typeof(GrowthController), "GetDamageMultiplier", null, "DamageMultiplier");
			Patch(harmony, typeof(GrowthController), "GetWeightSpeedReliefThreshold", null, "WeightThreshold");
			Patch(harmony, typeof(StatManager), "OnDamaged", "Damaging", null);
			Patch(harmony, typeof(VMonster), "OnDying", "MonsterDying", null);
			Patch(harmony, typeof(VPlayer), "OnDying", "PlayerDying", null);
			Patch(harmony, typeof(DungeonRoom), "Initialize", null, "DungeonInitialized");
			Patch(harmony, typeof(DungeonRoom), "SetDungeonState", "DungeonEnding", null);
			Patch(harmony, typeof(VRoomManager), "TerminateSession", "RunTerminated", null);
			Patch(harmony, typeof(VWaitingRoom), "OnAllMemberEntered", null, "TrainMembersEntered");
			Patch(harmony, typeof(VWaitingRoom), "OnRequestStartGame", "TrainDeparture", null);
			Patch(harmony, typeof(VWaitingRoom), "OnRequestEndSession", "TrainDeparture", null);
			Patch(harmony, typeof(NewTramLeverLevelObject), "TryInteract", "LocalTrainLever", null);
			Patch(harmony, typeof(IVroom), "LevelObjectEventInternal", "ChangingTrainLever", null);
			Patch(harmony, typeof(GameMainBase), "StartSceneLoading", "SceneLoading", null);
			Patch(harmony, typeof(GameMainBase), "EndSceneLoading", null, "SceneLoadingEnded");
			Patch(harmony, typeof(GamePlayScene), "IsCameraTargetOutdoor", null, "MonsterCameraOutdoor");
			Patch(harmony, typeof(InventoryController), "RecalculateSlotCount", null, "InventoryRecalculated", "InventoryLayoutTranspiler");
			Patch(harmony, typeof(InventoryController), "GetSlotKind", null, null, "SlotKindTranspiler");
			Patch(harmony, typeof(InventoryController), "IsSlotAvailableFor", null, "InventorySlotAvailable");
			Type nestedType = typeof(ProtoActor).GetNestedType("Inventory", BindingFlags.Public | BindingFlags.NonPublic);
			Patch(harmony, nestedType, "GetVisibleSlotIndices", null, "VisibleInventorySlots");
			Type nestedType2 = typeof(ProtoActor).GetNestedType("FakeJumper", BindingFlags.Public | BindingFlags.NonPublic);
			Patch(harmony, nestedType2, "TryStartJumpByInput", "JumpInput", null);
			Patch(harmony, typeof(ProtoActor), "IsMoveInputBlocked", null, "MoveInputBlocked");
			Patch(harmony, typeof(ProtoActor), "IsJumpInputBlocked", null, "MoveInputBlocked");
			Type type = AccessTools.TypeByName("Mimic.InputSystem.InputManager");
			Patch(harmony, type, "SetCapturing", "NativeCursorCapture", "NativeCursorUpdated");
			Patch(harmony, typeof(UIManager), "OpenInGameMenu", null, "NativeCursorUpdated");
			Patch(harmony, typeof(UIManager), "CloseInGameMenu", null, "NativeCursorUpdated");
			Patch(harmony, type, "IsCapturing", "NativeInputIsCapturing", null);
			Patch(harmony, type, "isPressed", "InputButton", null);
			Patch(harmony, type, "wasPressedThisFrame", "InputButton", null);
			Patch(harmony, type, "wasRelesedThisFrame", "InputButton", null);
			Patch(harmony, type, "get_mouseMovement", null, "InputVector");
			Patch(harmony, type, "get_gamepadLeftStick", null, "InputVector");
			Patch(harmony, type, "get_gamepadRightStick", null, "InputVector");
			MelonLogger.Msg("Power-Ups : " + installed + " points d'intégration du jeu chargés.");
		}

		private static void InstallSaveCreationHooks(Harmony harmony)
		{
			Patch(harmony, typeof(MainMenu), "CreateRoom", "MenuRoomCreating", null);
			Patch(harmony, typeof(VRoomManager), "InitMaintenenceRoom", "MaintenanceStarting", null);
			Patch(harmony, typeof(MaintenanceRoom), "SaveGameData", null, "MaintenanceSaved");
			Patch(harmony, typeof(GameSessionInfo), "ApplyLoadedGameData", null, "NativeSaveLoaded");
			MethodInfo[] methods = typeof(MainMenu).GetMethods(GameAdapter.All);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == "CreateNewGameInSlot")
				{
					try
					{
						harmony.Patch((MethodBase)methodInfo, Hook("NewGameRequested"), (HarmonyMethod)null, (HarmonyMethod)null, Hook("NewGameRequestEnded"), (HarmonyMethod)null);
						installed++;
					}
					catch (Exception ex)
					{
						MelonLogger.Warning("Power-Ups : détection nouvelle partie : " + ex.Message);
					}
				}
			}
		}

		private static void Patch(Harmony harmony, Type type, string method, string prefix, string postfix, string transpiler = null)
		{
			if (type == null)
			{
				MelonLogger.Warning("Power-Ups : type manquant pour " + method);
				return;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, method, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null);
			}
			if (methodInfo == null)
			{
				MelonLogger.Warning("Power-Ups : méthode manquante " + type.FullName + "." + method);
				return;
			}
			try
			{
				harmony.Patch((MethodBase)methodInfo, Hook(prefix), Hook(postfix), Hook(transpiler), (HarmonyMethod)null, (HarmonyMethod)null);
				installed++;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Power-Ups : intégration impossible pour " + type.FullName + "." + method + " : " + ex.Message);
			}
		}

		private static HarmonyMethod Hook(string name)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			if (name != null)
			{
				return new HarmonyMethod(typeof(GamePatches), name, (Type[])null);
			}
			return null;
		}

		private static void WorldInitialized(VWorld __instance)
		{
			if (Adapter != null)
			{
				Adapter.RegisterWorld(__instance);
			}
		}

		private static void NewGameRequested(int __1)
		{
			if (Adapter != null)
			{
				Adapter.NewGameRequested(__1);
			}
		}

		private static Exception NewGameRequestEnded(Exception __exception)
		{
			if (Adapter != null)
			{
				Adapter.NewGameRequestEnded();
			}
			return __exception;
		}

		private static void MenuRoomCreating()
		{
			if (Adapter != null)
			{
				Adapter.MenuRoomCreating();
			}
		}

		private static void MaintenanceStarting(VRoomManager __instance, int __1, bool __2)
		{
			if (Adapter != null)
			{
				Adapter.MaintenanceStarting(__instance, __1, __2);
			}
		}

		private static void MaintenanceSaved(MaintenanceRoom __instance, int __0, bool __2, MsgErrorCode __result)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (Adapter != null)
			{
				Adapter.MaintenanceSaved(__instance, __0, __2, __result);
			}
		}

		private static void NativeSaveLoaded(GameSessionInfo __instance)
		{
			if (Adapter != null)
			{
				Adapter.NativeSaveLoaded(__instance);
			}
		}

		private static void StatsLoading(StatManager __instance)
		{
			if (Adapter != null)
			{
				Adapter.RegisterStatManager(__instance);
			}
		}

		private static void StatsLoaded(StatManager __instance)
		{
			if (Adapter != null)
			{
				Adapter.RegisterStatManager(__instance);
			}
		}

		private static void ReadStat(CommonStats __instance, StatType __0, ref long __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (Adapter != null)
			{
				__result = Adapter.ScaleStat(__instance, __0, __result);
			}
		}

		private static void DamageMultiplier(GrowthController __instance, ref float __result)
		{
			if (Adapter != null)
			{
				__result = Adapter.ScaleStrength(__instance, __result);
			}
		}

		private static void WeightThreshold(GrowthController __instance, ref long __result)
		{
			if (Adapter != null)
			{
				__result = Adapter.ScaleWeight(__instance, __result);
			}
		}

		private static void Damaging(ApplyDamageArgs __0)
		{
			if (Adapter != null)
			{
				Adapter.Hit(__0);
			}
		}

		private static void MonsterDying(VMonster __instance, ActorDyingSig __0)
		{
			if (Adapter != null)
			{
				Adapter.MonsterDeath(__instance, __0);
			}
		}

		private static void PlayerDying(VPlayer __instance)
		{
			if (Adapter != null)
			{
				Adapter.PlayerDeath(__instance);
			}
		}

		private static void DungeonInitialized(DungeonRoom __instance, bool __result)
		{
			if (Adapter != null)
			{
				Adapter.RoomInitialized(__instance, __result);
			}
		}

		private static void DungeonEnding(DungeonRoom __instance, DungeonState __0)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (Adapter != null)
			{
				Adapter.RoomEnding(__instance, __0);
			}
		}

		private static void RunTerminated(VRoomManager __instance, RoomDrainInfo __1)
		{
			if (Adapter != null)
			{
				Adapter.RunTerminated(__instance, __1);
			}
		}

		private static void TrainMembersEntered(VWaitingRoom __instance)
		{
			if (Adapter != null)
			{
				Adapter.TrainMembersEntered(__instance);
			}
		}

		private static void SceneLoading(GameMainBase __instance)
		{
			if (Adapter != null)
			{
				Adapter.SceneLoading(__instance);
			}
		}

		private static void SceneLoadingEnded(GameMainBase __instance)
		{
			if (Adapter != null)
			{
				Adapter.SceneLoadingEnded(__instance);
			}
		}

		private static bool TrainDeparture(VWaitingRoom __instance, ref MsgErrorCode __result)
		{
			if (Adapter == null || Adapter.CanDepartTrain(__instance))
			{
				return true;
			}
			__result = (MsgErrorCode)20000024;
			return false;
		}

		private static bool LocalTrainLever(ProtoActor __0, ref bool __result)
		{
			if (Adapter == null || Adapter.CanUseDepartureLever(__0))
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool ChangingTrainLever(IVroom __instance, ILevelObjectInfo __0, int __3, ref MsgErrorCode __result)
		{
			if (Adapter == null || Adapter.CanChangeDepartureLever(__instance, __0, __3))
			{
				return true;
			}
			__result = (MsgErrorCode)20000024;
			return false;
		}

		private static void InventoryRecalculated(InventoryController __instance)
		{
			if (Adapter != null)
			{
				Adapter.InventoryChanged(__instance);
			}
		}

		private static void InventorySlotAvailable(InventoryController __instance, int __0, ref bool __result)
		{
			if (__result && Adapter != null && Adapter.IsInventorySlotBlocked(__instance, __0))
			{
				__result = false;
			}
		}

		private static IEnumerable<CodeInstruction> SlotKindTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo adjust = AccessTools.Method(typeof(GamePatches), "AdjustSlotKind", (Type[])null, (Type[])null);
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ret)
				{
					CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					MoveLabels(instruction, val);
					yield return val;
					yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null);
					yield return new CodeInstruction(OpCodes.Call, (object)adjust);
				}
				yield return instruction;
			}
		}

		private static int AdjustSlotKind(int kind, InventoryController inventory, int slot)
		{
			if (Adapter != null)
			{
				return Adapter.AdjustSlotKind(kind, inventory, slot);
			}
			return kind;
		}

		private static void MoveLabels(CodeInstruction from, CodeInstruction to)
		{
			FieldInfo? field = typeof(CodeInstruction).GetField("labels");
			IList list = field.GetValue(from) as IList;
			IList list2 = field.GetValue(to) as IList;
			if (list == null || list2 == null)
			{
				return;
			}
			foreach (object item in list)
			{
				list2.Add(item);
			}
			list.Clear();
		}

		private static IEnumerable<CodeInstruction> InventoryLayoutTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> codes = new List<CodeInstruction>(instructions);
			MethodInfo helper = AccessTools.Method(typeof(GamePatches), "NativeGenericSlotCount", (Type[])null, (Type[])null);
			bool replaced = false;
			for (int i = 0; i < codes.Count; i++)
			{
				if (!replaced && codes[i].opcode == OpCodes.Ldc_I4_4 && i + 2 < codes.Count && codes[i + 1].opcode == OpCodes.Ldarg_0)
				{
					MethodInfo methodInfo = codes[i + 2].operand as MethodInfo;
					if (methodInfo != null && methodInfo.Name == "GetDedicatedSlotCount")
					{
						CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
						MoveLabels(codes[i], val);
						yield return val;
						yield return new CodeInstruction(OpCodes.Call, (object)helper);
						replaced = true;
						continue;
					}
				}
				yield return codes[i];
			}
			if (!replaced)
			{
				MelonLogger.Warning("Power-Ups : disposition native de l'inventaire non reconnue; cinquième emplacement à vérifier.");
			}
		}

		private static int NativeGenericSlotCount(InventoryController inventory)
		{
			if (Adapter != null)
			{
				return Adapter.NativeGenericSlotCount(inventory);
			}
			return 4;
		}

		private static void VisibleInventorySlots(object __instance, ref List<int> __result)
		{
			if (Adapter == null || __result == null)
			{
				return;
			}
			object obj = GameAdapter.Read(__instance, "owner");
			ProtoActor val = (ProtoActor)((obj is ProtoActor) ? obj : null);
			if ((Object)(object)val == (Object)null || val.steamID == 0L)
			{
				return;
			}
			List<int> list = new List<int>();
			foreach (int item in __result)
			{
				if (!Adapter.IsSlotHidden(val, item))
				{