Decompiled source of TundrasInstancer v1.0.0

TundrasInstancer.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using AtlyssCommandLib.API;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Mirror;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Guid("8f2a7c14-6b03-4d9e-a157-3c8b0e6d42f9")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyTitle("TundrasInstancer")]
[assembly: AssemblyProduct("TundrasInstancer")]
[assembly: AssemblyDescription("Private map instances on command.")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace tundras_instancer;

internal struct MapEntry
{
	internal string ScenePath;

	internal string Caption;

	internal string SpawnTag;
}
internal static class MapCatalog
{
	internal static List<MapEntry> Gather()
	{
		List<MapEntry> list = new List<MapEntry>();
		Portal[] array = Resources.FindObjectsOfTypeAll<Portal>();
		for (int i = 0; i < array.Length; i++)
		{
			ScenePortalData scenePortal = array[i]._scenePortal;
			if (scenePortal != null)
			{
				Add(list, scenePortal._subScene, scenePortal._portalCaptionTitle, scenePortal._spawnPointTag);
			}
		}
		ScriptableMapData[] array2 = Resources.FindObjectsOfTypeAll<ScriptableMapData>();
		for (int j = 0; j < array2.Length; j++)
		{
			Add(list, array2[j]._subScene, array2[j]._mapCaptionTitle, array2[j]._spawnPointTag);
		}
		return list;
	}

	private static void Add(List<MapEntry> found, string scenePath, string caption, string spawnTag)
	{
		if (string.IsNullOrEmpty(scenePath))
		{
			return;
		}
		for (int i = 0; i < found.Count; i++)
		{
			if (found[i].ScenePath == scenePath)
			{
				return;
			}
		}
		found.Add(new MapEntry
		{
			ScenePath = scenePath,
			Caption = (string.IsNullOrEmpty(caption) ? Key(scenePath) : caption),
			SpawnTag = (string.IsNullOrEmpty(spawnTag) ? "spawnPoint" : spawnTag)
		});
	}

	internal static string Key(string scenePath)
	{
		if (string.IsNullOrEmpty(scenePath))
		{
			return "";
		}
		int num = scenePath.LastIndexOf('/');
		string text = ((num < 0) ? scenePath : scenePath.Substring(num + 1));
		if (text.EndsWith(".unity", StringComparison.OrdinalIgnoreCase))
		{
			text = text.Substring(0, text.Length - 6);
		}
		return text;
	}

	internal static bool IsVanilla(string scenePath)
	{
		return SceneUtility.GetBuildIndexByScenePath(scenePath) >= 0;
	}

	internal static bool Resolve(string wanted, out MapEntry match)
	{
		match = default(MapEntry);
		if (string.IsNullOrEmpty(wanted))
		{
			return false;
		}
		string text = Flatten(wanted);
		List<MapEntry> list = Gather();
		for (int i = 0; i < list.Count; i++)
		{
			if (Flatten(Key(list[i].ScenePath)) == text || Flatten(list[i].Caption) == text)
			{
				match = list[i];
				return true;
			}
		}
		for (int j = 0; j < list.Count; j++)
		{
			if (Flatten(Key(list[j].ScenePath)).Contains(text) || Flatten(list[j].Caption).Contains(text))
			{
				match = list[j];
				return true;
			}
		}
		return false;
	}

	private static string Flatten(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return "";
		}
		return value.Replace(" ", "").Replace("_", "").ToLowerInvariant();
	}
}
internal static class InstanceCommands
{
	private static readonly Color Notice = new Color(0.6f, 0.85f, 1f);

	private static readonly Color Problem = new Color(1f, 0.55f, 0.5f);

	internal static void Register()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Expected O, but got Unknown
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Expected O, but got Unknown
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		try
		{
			CommandProvider val = new CommandProvider("instance", "Private map instances");
			val.RegisterCommand("go", "Open a private instance of a map and travel to it", "instance go <map name>", new CommandCallback(Go), (CommandOptions?)new CommandOptions((ChatCommandType)3));
			val.RegisterCommand("maps", "List maps that can be instanced", new CommandCallback(Maps), (CommandOptions?)new CommandOptions((ChatCommandType)3));
			val.RegisterCommand("list", "List the private instances that are open right now", new CommandCallback(ListOpen), (CommandOptions?)new CommandOptions((ChatCommandType)2));
			val.RegisterCommand("leave", "Return to the hub from a private instance", new CommandCallback(Leave), (CommandOptions?)new CommandOptions((ChatCommandType)3));
			val.RegisterCommand("close", "Give up the private instance you opened", new CommandCallback(Close), (CommandOptions?)new CommandOptions((ChatCommandType)3));
			Utils.RegisterProvider(val);
			Log.Info("registered /instance with go, maps, list, leave and close");
		}
		catch (Exception ex)
		{
			Log.Warn("could not register commands, " + ex.Message);
		}
	}

	private static bool Go(Caller caller, string[] args)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		Player player = caller.player;
		if (!NetworkServer.active || (Object)(object)player == (Object)null)
		{
			return true;
		}
		if (args == null || args.Length == 0)
		{
			return false;
		}
		if (TundrasInstancerConfig.HostOnly.Value && !((Caller)(ref caller)).isHost)
		{
			Utils.NotifyCaller(caller, "Only the host can open private instances here.", Problem);
			return true;
		}
		string text = string.Join(" ", args);
		if (!MapCatalog.Resolve(text, out var match))
		{
			Utils.NotifyCaller(caller, "No map called " + text + ". Try /instance maps.", Problem);
			return true;
		}
		if (!TundrasInstancerConfig.AllowVanillaMaps.Value && MapCatalog.IsVanilla(match.ScenePath))
		{
			Utils.NotifyCaller(caller, match.Caption + " is a vanilla map and instancing it is disabled.", Problem);
			return true;
		}
		MapInstancingManager current = MapInstancingManager._current;
		if ((Object)(object)current == (Object)null)
		{
			Utils.NotifyCaller(caller, "The world is not ready yet, try again in a moment.", Problem);
			return true;
		}
		MapInstance val = InstanceRegistry.FindAdmitting(match.ScenePath, player);
		if ((Object)(object)val != (Object)null)
		{
			Utils.NotifyCaller(caller, "Rejoining your instance of " + match.Caption + ".", Notice);
		}
		else
		{
			InstanceClaim instanceClaim = InstanceRegistry.FindOwnedBy(player);
			if (instanceClaim != null)
			{
				Utils.NotifyCaller(caller, "You already have " + MapCatalog.Key(instanceClaim.ScenePath) + " open. Use /instance close first, or /instance go " + MapCatalog.Key(instanceClaim.ScenePath) + " to return to it.", Problem);
				return true;
			}
			InstanceRequests.Add(player);
			Utils.NotifyCaller(caller, "Opening a private instance of " + match.Caption + ".", Notice);
		}
		Scene scene = ((Component)player).gameObject.scene;
		current.Init_SendPeer_ToScene(player, ((Scene)(ref scene)).path, match.ScenePath, match.SpawnTag, (ZoneDifficulty)1);
		return true;
	}

	private static int PeersInside(InstanceClaim claim)
	{
		if ((Object)(object)claim.Instance == (Object)null || claim.Instance._peersInInstance == null)
		{
			return 0;
		}
		return claim.Instance._peersInInstance.Count;
	}

	private static int OthersInside(InstanceClaim claim, Player except)
	{
		if ((Object)(object)claim.Instance == (Object)null || claim.Instance._peersInInstance == null)
		{
			return 0;
		}
		int num = 0;
		List<Player> peersInInstance = claim.Instance._peersInInstance;
		for (int i = 0; i < peersInInstance.Count; i++)
		{
			if ((Object)(object)peersInInstance[i] != (Object)null && (Object)(object)peersInInstance[i] != (Object)(object)except)
			{
				num++;
			}
		}
		return num;
	}

	private static bool Maps(Caller caller, string[] args)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		List<MapEntry> list = MapCatalog.Gather();
		if (list.Count == 0)
		{
			Utils.NotifyCaller(caller, "No maps found yet, load into the world first.", Problem);
			return true;
		}
		for (int i = 0; i < list.Count; i++)
		{
			string text = (MapCatalog.IsVanilla(list[i].ScenePath) ? "" : "  (modded)");
			Utils.NotifyCaller(caller, MapCatalog.Key(list[i].ScenePath) + "  -  " + list[i].Caption + text, Notice);
		}
		return true;
	}

	private static bool ListOpen(Caller caller, string[] args)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		if (!((Caller)(ref caller)).isHost)
		{
			Utils.NotifyCaller(caller, "Only the host can see who has an instance open.", Problem);
			return true;
		}
		IList<InstanceClaim> all = InstanceRegistry.All;
		if (all.Count == 0)
		{
			Utils.NotifyCaller(caller, "No private instances are open.", Notice);
			return true;
		}
		for (int i = 0; i < all.Count; i++)
		{
			Utils.NotifyCaller(caller, MapCatalog.Key(all[i].ScenePath) + "  owner " + all[i].OwnerName() + "  peers " + PeersInside(all[i]), Notice);
		}
		return true;
	}

	private static bool Close(Caller caller, string[] args)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		Player player = caller.player;
		if (!NetworkServer.active || (Object)(object)player == (Object)null)
		{
			return true;
		}
		InstanceClaim instanceClaim = InstanceRegistry.FindOwnedBy(player);
		if (instanceClaim == null)
		{
			Utils.NotifyCaller(caller, "You do not have an instance open.", Problem);
			return true;
		}
		int num = OthersInside(instanceClaim, player);
		string text = MapCatalog.Key(instanceClaim.ScenePath);
		InstanceRegistry.Release(player);
		if (num > 0)
		{
			Utils.NotifyCaller(caller, "Gave up " + text + ". " + num + " still inside, it closes when they leave.", Notice);
		}
		else
		{
			Utils.NotifyCaller(caller, "Gave up " + text + ". You can open another now.", Notice);
		}
		return true;
	}

	private static bool Leave(Caller caller, string[] args)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		Player player = caller.player;
		if (!NetworkServer.active || (Object)(object)player == (Object)null)
		{
			return true;
		}
		MapInstancingManager current = MapInstancingManager._current;
		if ((Object)(object)current == (Object)null)
		{
			return true;
		}
		Scene scene = ((Component)player).gameObject.scene;
		current.Init_SendPeer_ToScene(player, ((Scene)(ref scene)).path, current._hubMap, current._hubMainSpawnPointTag, (ZoneDifficulty)1);
		Utils.NotifyCaller(caller, "Returning to the hub.", Notice);
		return true;
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("com.tundra.atlyss.tundrasinstancer", "Tundra's Instancer", "1.0.0")]
public class TundrasInstancerPlugin : BaseUnityPlugin
{
	internal const string PluginGuid = "com.tundra.atlyss.tundrasinstancer";

	private void Awake()
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Expected O, but got Unknown
		Log.Init(((BaseUnityPlugin)this).Logger);
		TundrasInstancerConfig.Init(((BaseUnityPlugin)this).Config);
		InstanceCommands.Register();
		InstancePatches.Apply(new Harmony("com.tundra.atlyss.tundrasinstancer"));
		Log.Info("ready");
	}

	private void Update()
	{
		InstanceSleeper.Tick();
	}

	private void OnDestroy()
	{
		InstanceSleeper.WakeAll();
	}
}
internal static class Log
{
	private static ManualLogSource _source;

	internal static void Init(ManualLogSource source)
	{
		_source = source;
	}

	internal static void Info(string message)
	{
		if (_source != null)
		{
			_source.LogInfo((object)message);
		}
	}

	internal static void Warn(string message)
	{
		if (_source != null)
		{
			_source.LogWarning((object)message);
		}
	}
}
internal static class TundrasInstancerConfig
{
	internal static ConfigEntry<bool> HostOnly;

	internal static ConfigEntry<bool> AllowVanillaMaps;

	internal static ConfigEntry<bool> SleepIdleInstances;

	internal static ConfigEntry<bool> SleepCreepVisuals;

	internal static void Init(ConfigFile config)
	{
		HostOnly = config.Bind<bool>("Access", "HostOnly", false, "When true only the host may open a private instance.");
		AllowVanillaMaps = config.Bind<bool>("Access", "AllowVanillaMaps", true, "When false only maps added by MapLoader may be instanced, leaving the vanilla world alone.");
		SleepIdleInstances = config.Bind<bool>("Performance", "SleepIdleInstances", true, "On the host, stops drawing props, lights, cameras and particles in instances you are not standing in.");
		SleepCreepVisuals = config.Bind<bool>("Performance", "SleepCreepVisuals", true, "Also stops drawing and animating monsters in those instances. Only affects your own screen, other players still see them.");
	}
}
internal sealed class InstanceClaim
{
	internal MapInstance Instance;

	internal string ScenePath;

	internal PartyObjectBehavior Party;

	internal Player Owner;

	internal string OwnerId;

	internal string OwnerLabel;

	internal bool Admits(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		if (InstanceRegistry.SameOwner(this, player))
		{
			return true;
		}
		if ((Object)(object)Owner != (Object)null)
		{
			Party = Owner.Network_partyObject;
		}
		if ((Object)(object)Party != (Object)null)
		{
			return (Object)(object)player.Network_partyObject == (Object)(object)Party;
		}
		return false;
	}

	internal string OwnerName()
	{
		if ((Object)(object)Owner != (Object)null && !string.IsNullOrEmpty(Owner._nickname))
		{
			return Owner._nickname;
		}
		if (!string.IsNullOrEmpty(OwnerLabel))
		{
			return OwnerLabel;
		}
		return "someone who left";
	}
}
internal static class InstanceRegistry
{
	private static readonly List<InstanceClaim> Claims = new List<InstanceClaim>();

	internal static IList<InstanceClaim> All
	{
		get
		{
			Prune();
			return Claims;
		}
	}

	internal static void Prune()
	{
		for (int num = Claims.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)Claims[num].Instance == (Object)null)
			{
				Log.Info("private instance of " + Claims[num].ScenePath + " was unloaded");
				Claims.RemoveAt(num);
			}
		}
	}

	internal static string IdentityOf(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		string steamID = player._steamID;
		if (!string.IsNullOrEmpty(steamID))
		{
			return steamID;
		}
		return null;
	}

	internal static bool SameOwner(InstanceClaim claim, Player player)
	{
		if (claim == null || (Object)(object)player == (Object)null)
		{
			return false;
		}
		string text = IdentityOf(player);
		if (text != null && text == claim.OwnerId)
		{
			return true;
		}
		return (Object)(object)claim.Owner == (Object)(object)player;
	}

	internal static InstanceClaim FindOwnedBy(Player owner)
	{
		if ((Object)(object)owner == (Object)null)
		{
			return null;
		}
		Prune();
		foreach (InstanceClaim claim in Claims)
		{
			if (SameOwner(claim, owner))
			{
				return claim;
			}
		}
		return null;
	}

	internal static bool Release(Player owner)
	{
		InstanceClaim instanceClaim = FindOwnedBy(owner);
		if (instanceClaim == null)
		{
			return false;
		}
		Claims.Remove(instanceClaim);
		Log.Info("released the private instance of " + instanceClaim.ScenePath + " owned by " + instanceClaim.OwnerName());
		return true;
	}

	internal static void Add(MapInstance instance, string scenePath, Player owner)
	{
		InstanceClaim instanceClaim = FindOwnedBy(owner);
		if (instanceClaim != null)
		{
			Log.Warn(instanceClaim.OwnerName() + " already owns an instance of " + instanceClaim.ScenePath + ", not claiming another");
			return;
		}
		InstanceClaim instanceClaim2 = new InstanceClaim();
		instanceClaim2.Instance = instance;
		instanceClaim2.ScenePath = scenePath;
		instanceClaim2.Owner = owner;
		instanceClaim2.OwnerId = IdentityOf(owner);
		instanceClaim2.OwnerLabel = (((Object)(object)owner == (Object)null) ? null : owner._nickname);
		instanceClaim2.Party = (((Object)(object)owner == (Object)null) ? null : owner.Network_partyObject);
		Claims.Add(instanceClaim2);
		Log.Info("claimed a private instance of " + scenePath + " for " + instanceClaim2.OwnerName());
	}

	internal static bool HasAnyFor(string scenePath)
	{
		Prune();
		foreach (InstanceClaim claim in Claims)
		{
			if (claim.ScenePath == scenePath)
			{
				return true;
			}
		}
		return false;
	}

	internal static bool IsPrivate(MapInstance instance)
	{
		Prune();
		foreach (InstanceClaim claim in Claims)
		{
			if ((Object)(object)claim.Instance == (Object)(object)instance)
			{
				return true;
			}
		}
		return false;
	}

	internal static MapInstance FindAdmitting(string scenePath, Player player)
	{
		Prune();
		foreach (InstanceClaim claim in Claims)
		{
			if (claim.ScenePath == scenePath && claim.Admits(player))
			{
				return claim.Instance;
			}
		}
		return null;
	}
}
internal static class InstanceRequests
{
	private static readonly List<Player> Pending = new List<Player>();

	internal static void Add(Player player)
	{
		for (int num = Pending.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)Pending[num] == (Object)null)
			{
				Pending.RemoveAt(num);
			}
		}
		if ((Object)(object)player != (Object)null && !Pending.Contains(player))
		{
			Pending.Add(player);
		}
	}

	internal static bool Consume(Player player)
	{
		if ((Object)(object)player != (Object)null)
		{
			return Pending.Remove(player);
		}
		return false;
	}
}
internal sealed class SleptInstance
{
	internal MapInstance Instance;

	internal List<Renderer> Renderers = new List<Renderer>();

	internal List<Behaviour> Behaviours = new List<Behaviour>();

	internal List<ParticleSystem> Particles = new List<ParticleSystem>();

	internal List<AudioSource> Audio = new List<AudioSource>();

	internal List<Animator> Animators = new List<Animator>();
}
internal static class InstanceSleeper
{
	private static readonly List<SleptInstance> Slept = new List<SleptInstance>();

	private static bool _describedAoi;

	internal static void Tick()
	{
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		if (!TundrasInstancerConfig.SleepIdleInstances.Value || !NetworkServer.active)
		{
			return;
		}
		Player mainPlayer = Player._mainPlayer;
		MapInstancingManager current = MapInstancingManager._current;
		if ((Object)(object)mainPlayer == (Object)null || (Object)(object)current == (Object)null)
		{
			return;
		}
		DescribeAoiOnce();
		Scene scene = ((Component)mainPlayer).gameObject.scene;
		for (int num = Slept.Count - 1; num >= 0; num--)
		{
			SleptInstance sleptInstance = Slept[num];
			if ((Object)(object)sleptInstance.Instance == (Object)null)
			{
				Slept.RemoveAt(num);
			}
			else if (sleptInstance.Instance._loadedScene == scene)
			{
				Wake(sleptInstance);
				Slept.RemoveAt(num);
			}
		}
		foreach (MapInstance loadedInstance in current._loadedInstances)
		{
			if (!((Object)(object)loadedInstance == (Object)null) && !(loadedInstance._loadedScene == scene) && ((Scene)(ref loadedInstance._loadedScene)).IsValid() && !IsSlept(loadedInstance))
			{
				Sleep(loadedInstance);
			}
		}
	}

	internal static void WakeAll()
	{
		foreach (SleptInstance item in Slept)
		{
			if ((Object)(object)item.Instance != (Object)null)
			{
				Wake(item);
			}
		}
		Slept.Clear();
	}

	private static bool IsSlept(MapInstance instance)
	{
		foreach (SleptInstance item in Slept)
		{
			if ((Object)(object)item.Instance == (Object)(object)instance)
			{
				return true;
			}
		}
		return false;
	}

	private static void Sleep(MapInstance instance)
	{
		SleptInstance sleptInstance = new SleptInstance();
		sleptInstance.Instance = instance;
		Transform environment = (((Object)(object)instance._environmentGroup == (Object)null) ? null : instance._environmentGroup.transform);
		GameObject[] rootGameObjects = ((Scene)(ref instance._loadedScene)).GetRootGameObjects();
		foreach (GameObject val in rootGameObjects)
		{
			Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (val2.enabled && !Skip(((Component)val2).transform, environment))
				{
					val2.enabled = false;
					sleptInstance.Renderers.Add(val2);
				}
			}
			Light[] componentsInChildren2 = val.GetComponentsInChildren<Light>(true);
			foreach (Light val3 in componentsInChildren2)
			{
				if (((Behaviour)val3).enabled && !Skip(((Component)val3).transform, environment))
				{
					((Behaviour)val3).enabled = false;
					sleptInstance.Behaviours.Add((Behaviour)(object)val3);
				}
			}
			Camera[] componentsInChildren3 = val.GetComponentsInChildren<Camera>(true);
			foreach (Camera val4 in componentsInChildren3)
			{
				if (((Behaviour)val4).enabled && !Skip(((Component)val4).transform, null))
				{
					((Behaviour)val4).enabled = false;
					sleptInstance.Behaviours.Add((Behaviour)(object)val4);
				}
			}
			ReflectionProbe[] componentsInChildren4 = val.GetComponentsInChildren<ReflectionProbe>(true);
			foreach (ReflectionProbe val5 in componentsInChildren4)
			{
				if (((Behaviour)val5).enabled)
				{
					((Behaviour)val5).enabled = false;
					sleptInstance.Behaviours.Add((Behaviour)(object)val5);
				}
			}
			ParticleSystem[] componentsInChildren5 = val.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val6 in componentsInChildren5)
			{
				if (val6.isPlaying && !Skip(((Component)val6).transform, null))
				{
					val6.Pause(false);
					sleptInstance.Particles.Add(val6);
				}
			}
			AudioSource[] componentsInChildren6 = val.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource val7 in componentsInChildren6)
			{
				if (val7.isPlaying && !Skip(((Component)val7).transform, null))
				{
					val7.Pause();
					sleptInstance.Audio.Add(val7);
				}
			}
			Animator[] componentsInChildren7 = val.GetComponentsInChildren<Animator>(true);
			foreach (Animator val8 in componentsInChildren7)
			{
				if (((Behaviour)val8).enabled && !Skip(((Component)val8).transform, null))
				{
					((Behaviour)val8).enabled = false;
					sleptInstance.Animators.Add(val8);
				}
			}
		}
		Slept.Add(sleptInstance);
		Log.Info("slept " + instance._mapName + ": " + sleptInstance.Renderers.Count + " renderers, " + sleptInstance.Behaviours.Count + " lights/cameras/probes, " + sleptInstance.Particles.Count + " particle systems, " + sleptInstance.Audio.Count + " audio sources, " + sleptInstance.Animators.Count + " animators");
	}

	private static void Wake(SleptInstance slept)
	{
		foreach (Renderer renderer in slept.Renderers)
		{
			if ((Object)(object)renderer != (Object)null)
			{
				renderer.enabled = true;
			}
		}
		foreach (Behaviour behaviour in slept.Behaviours)
		{
			if ((Object)(object)behaviour != (Object)null)
			{
				behaviour.enabled = true;
			}
		}
		foreach (ParticleSystem particle in slept.Particles)
		{
			if ((Object)(object)particle != (Object)null)
			{
				particle.Play(false);
			}
		}
		foreach (AudioSource item in slept.Audio)
		{
			if ((Object)(object)item != (Object)null)
			{
				item.UnPause();
			}
		}
		foreach (Animator animator in slept.Animators)
		{
			if ((Object)(object)animator != (Object)null)
			{
				((Behaviour)animator).enabled = true;
			}
		}
		Log.Info("woke " + slept.Instance._mapName);
	}

	private static bool Skip(Transform transform, Transform environment)
	{
		if ((Object)(object)environment != (Object)null && transform.IsChildOf(environment))
		{
			return true;
		}
		if ((Object)(object)((Component)transform).GetComponentInParent<Player>() != (Object)null)
		{
			return true;
		}
		if (TundrasInstancerConfig.SleepCreepVisuals.Value)
		{
			return false;
		}
		return (Object)(object)((Component)transform).GetComponentInParent<NetworkIdentity>() != (Object)null;
	}

	private static void DescribeAoiOnce()
	{
		if (!_describedAoi)
		{
			_describedAoi = true;
			InterestManagementBase aoi = NetworkServer.aoi;
			Log.Info("interest management: " + (((Object)(object)aoi == (Object)null) ? "none, every client receives every instance" : ((object)aoi).GetType().Name));
		}
	}
}
internal static class InstancePatches
{
	internal static void Apply(Harmony harmony)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(MapInstancingManager), "Init_SendPeer_ToScene", (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			Log.Warn("MapInstancingManager.Init_SendPeer_ToScene is gone, private instances cannot work");
			return;
		}
		try
		{
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(InstancePatches), "Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		catch (Exception ex)
		{
			Log.Warn("could not patch the instancing manager, " + ex.Message);
		}
	}

	private static bool Prefix(Player _player, string _old, string _new, string _spawnTag, ZoneDifficulty _difficulty)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if (!NetworkServer.active || (Object)(object)_player == (Object)null || string.IsNullOrEmpty(_new))
		{
			return true;
		}
		bool flag = InstanceRequests.Consume(_player);
		if (!flag && !InstanceRegistry.HasAnyFor(_new))
		{
			return true;
		}
		InstanceTransport.Begin(_player, _old, _new, _spawnTag, _difficulty, flag);
		return false;
	}
}
internal static class InstanceTransport
{
	private const float FindTimeout = 20f;

	private const float ReadyTimeout = 30f;

	private const float GateTimeout = 60f;

	private static readonly Dictionary<string, int> QueueHolds = new Dictionary<string, int>();

	private static bool _loadInFlight;

	private static float _loadStarted;

	private static MapInstancingManager _bound;

	private static void Bind(MapInstancingManager manager)
	{
		if (!((Object)(object)_bound == (Object)(object)manager))
		{
			_bound = manager;
			_loadInFlight = false;
			QueueHolds.Clear();
		}
	}

	private static bool LoadStillInFlight()
	{
		if (!_loadInFlight)
		{
			return false;
		}
		if (Time.realtimeSinceStartup - _loadStarted <= 60f)
		{
			return true;
		}
		Log.Warn("a previous instance load never finished, clearing the gate");
		_loadInFlight = false;
		return false;
	}

	internal static void Begin(Player player, string oldScene, string newScene, string spawnTag, ZoneDifficulty difficulty, bool forcePrivate)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		MapInstancingManager current = MapInstancingManager._current;
		if ((Object)(object)current == (Object)null)
		{
			Log.Warn("no instancing manager, the transport was dropped");
		}
		else
		{
			((MonoBehaviour)current).StartCoroutine(Run(current, player, oldScene, newScene, spawnTag, difficulty, forcePrivate));
		}
	}

	private static IEnumerator Run(MapInstancingManager manager, Player player, string oldScene, string newScene, string spawnTag, ZoneDifficulty difficulty, bool forcePrivate)
	{
		if ((Object)(object)manager == (Object)null || (Object)(object)player == (Object)null)
		{
			yield break;
		}
		Bind(manager);
		string who = player._nickname;
		Log.Info("transport start, " + who + " to " + newScene + (forcePrivate ? " (private)" : ""));
		player.Network_currentGameCondition = (GameCondition)0;
		yield return (object)new WaitForSeconds(1.25f);
		if ((Object)(object)player == (Object)null)
		{
			yield break;
		}
		MapInstance target = (forcePrivate ? null : InstanceRegistry.FindAdmitting(newScene, player));
		if ((Object)(object)target == (Object)null && !forcePrivate)
		{
			target = FindPublic(manager, newScene, player);
		}
		bool weLoaded = false;
		if ((Object)(object)target == (Object)null)
		{
			float gateWaited = 0f;
			while (LoadStillInFlight() && gateWaited < 60f)
			{
				gateWaited += Time.deltaTime;
				yield return null;
			}
			if (LoadStillInFlight())
			{
				Restore(player, "another instance is still loading, try again in a moment");
				yield break;
			}
			_loadInFlight = true;
			_loadStarted = Time.realtimeSinceStartup;
			HoldQueue(manager, newScene);
			weLoaded = true;
			HashSet<int> before = HandlesFor(newScene);
			Log.Info("loading a copy of " + newScene + ", " + before.Count + " already open");
			IEnumerator load = LoadCopy(newScene);
			while (load.MoveNext())
			{
				yield return load.Current;
			}
			Scene loaded = NewSceneFor(newScene, before);
			_loadInFlight = false;
			if (!((Scene)(ref loaded)).IsValid())
			{
				ReleaseQueue(manager, newScene);
				Restore(player, newScene + " did not load");
				yield break;
			}
			float waited = 0f;
			while (waited < 20f)
			{
				target = FindInScene(manager, loaded);
				if ((Object)(object)target != (Object)null)
				{
					break;
				}
				waited += Time.deltaTime;
				yield return null;
			}
			if ((Object)(object)target == (Object)null)
			{
				ReleaseQueue(manager, newScene);
				Restore(player, newScene + " loaded but never registered a MapInstance");
				yield break;
			}
			Log.Info("instance ready, " + target._mapName + " handle " + ((Scene)(ref loaded)).handle);
			if (forcePrivate)
			{
				InstanceRegistry.Add(target, newScene, player);
			}
		}
		if ((Object)(object)player == (Object)null)
		{
			if (weLoaded)
			{
				ReleaseQueue(manager, newScene);
			}
			yield break;
		}
		if (player._isHostPlayer)
		{
			DropHostColliders(manager, ((Component)player).gameObject.scene);
		}
		SceneManager.MoveGameObjectToScene(((Component)player).gameObject, SceneManager.GetActiveScene());
		yield return (object)new WaitForSeconds(0.45f);
		if ((Object)(object)player == (Object)null || (Object)(object)target == (Object)null)
		{
			if (weLoaded)
			{
				ReleaseQueue(manager, newScene);
			}
			yield break;
		}
		SceneManager.MoveGameObjectToScene(((Component)player).gameObject, target._loadedScene);
		((Component)player).transform.SetAsLastSibling();
		if (!target._peersInInstance.Contains(player))
		{
			target._peersInInstance.Add(player);
		}
		target.SendPeer_ToSpawnPoint(((Component)player).gameObject, spawnTag);
		if ((int)target._zoneType != 0)
		{
			player._statusEntity.Replenish_All();
		}
		NetworkConnectionToClient conn = ((NetworkBehaviour)player).connectionToClient;
		if (conn != null)
		{
			((NetworkConnection)conn).Send<SceneMessage>(new SceneMessage
			{
				sceneName = newScene,
				sceneOperation = (SceneOperation)1
			}, 0);
			float readyWaited = 0f;
			while (!((NetworkConnection)conn).isReady && readyWaited < 30f)
			{
				readyWaited += Time.deltaTime;
				yield return null;
			}
			if (!((NetworkConnection)conn).isReady)
			{
				Log.Warn(who + " never reported ready, continuing anyway");
			}
			if (!string.IsNullOrEmpty(oldScene) && oldScene != newScene)
			{
				((NetworkConnection)conn).Send<SceneMessage>(new SceneMessage
				{
					sceneName = oldScene,
					sceneOperation = (SceneOperation)2
				}, 0);
			}
		}
		yield return (object)new WaitForSeconds(0.85f);
		if ((Object)(object)player != (Object)null && (Object)(object)target != (Object)null)
		{
			if ((Object)(object)Player._mainPlayer == (Object)(object)player && player._isHostPlayer)
			{
				target.Spawn_HostCameraColliders();
			}
			player.Network_playerZoneType = target._zoneType;
			player.Network_currentGameCondition = (GameCondition)1;
			player.Network_currentPlayerCondition = (PlayerCondition)2;
			player._lastSpawnPoint = spawnTag;
			Log.Info("transport done, " + who + " is in " + target._mapName);
		}
		if (weLoaded)
		{
			ReleaseQueue(manager, newScene);
		}
	}

	private static IEnumerator LoadCopy(string scenePath)
	{
		AsyncOperation op = null;
		try
		{
			op = SceneManager.LoadSceneAsync(scenePath, new LoadSceneParameters((LoadSceneMode)1, (LocalPhysicsMode)2));
		}
		catch (Exception ex)
		{
			Log.Warn("could not start loading " + scenePath + ", " + ex.Message);
		}
		if (op != null)
		{
			while (!op.isDone)
			{
				yield return null;
			}
		}
	}

	private static HashSet<int> HandlesFor(string scenePath)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < SceneManager.sceneCount; i++)
		{
			Scene sceneAt = SceneManager.GetSceneAt(i);
			if (((Scene)(ref sceneAt)).path == scenePath)
			{
				hashSet.Add(((Scene)(ref sceneAt)).handle);
			}
		}
		return hashSet;
	}

	private static Scene NewSceneFor(string scenePath, HashSet<int> before)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < SceneManager.sceneCount; i++)
		{
			Scene sceneAt = SceneManager.GetSceneAt(i);
			if (((Scene)(ref sceneAt)).path == scenePath && !before.Contains(((Scene)(ref sceneAt)).handle))
			{
				return sceneAt;
			}
		}
		return default(Scene);
	}

	private static MapInstance FindPublic(MapInstancingManager manager, string scenePath, Player player)
	{
		for (int i = 0; i < manager._loadedInstances.Count; i++)
		{
			MapInstance val = manager._loadedInstances[i];
			if ((Object)(object)val == (Object)null || ((Scene)(ref val._loadedScene)).path != scenePath || InstanceRegistry.IsPrivate(val))
			{
				continue;
			}
			PatternInstanceManager patternInstance = val._patternInstance;
			if ((Object)(object)patternInstance != (Object)null)
			{
				PartyObjectBehavior network_instanceParty = patternInstance.Network_instanceParty;
				if ((Object)(object)network_instanceParty != (Object)null && (Object)(object)player.Network_partyObject != (Object)(object)network_instanceParty)
				{
					continue;
				}
			}
			return val;
		}
		return null;
	}

	private static void DropHostColliders(MapInstancingManager manager, Scene leaving)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < manager._loadedInstances.Count; i++)
		{
			MapInstance val = manager._loadedInstances[i];
			if ((Object)(object)val != (Object)null && val._loadedScene == leaving)
			{
				val.Destroy_HostCameraColliders();
			}
		}
	}

	private static MapInstance FindInScene(MapInstancingManager manager, Scene scene)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < manager._loadedInstances.Count; i++)
		{
			MapInstance val = manager._loadedInstances[i];
			if ((Object)(object)val != (Object)null)
			{
				Scene scene2 = ((Component)val).gameObject.scene;
				if (((Scene)(ref scene2)).handle == ((Scene)(ref scene)).handle)
				{
					return val;
				}
			}
		}
		return null;
	}

	private static void HoldQueue(MapInstancingManager manager, string scenePath)
	{
		QueueHolds.TryGetValue(scenePath, out var value);
		QueueHolds[scenePath] = value + 1;
		if (!manager._instanceQueue.Contains(scenePath))
		{
			manager._instanceQueue.Add(scenePath);
		}
	}

	private static void ReleaseQueue(MapInstancingManager manager, string scenePath)
	{
		if (QueueHolds.TryGetValue(scenePath, out var value))
		{
			value--;
			if (value > 0)
			{
				QueueHolds[scenePath] = value;
				return;
			}
			QueueHolds.Remove(scenePath);
			manager._instanceQueue.Remove(scenePath);
		}
	}

	private static void Restore(Player player, string reason)
	{
		Log.Warn("transport aborted, " + reason);
		if (!((Object)(object)player == (Object)null))
		{
			player.Network_currentGameCondition = (GameCondition)1;
			player.Network_currentPlayerCondition = (PlayerCondition)2;
		}
	}
}