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 Gather() { List list = new List(); Portal[] array = Resources.FindObjectsOfTypeAll(); 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(); 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 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 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 ", 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 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 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 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 HostOnly; internal static ConfigEntry AllowVanillaMaps; internal static ConfigEntry SleepIdleInstances; internal static ConfigEntry SleepCreepVisuals; internal static void Init(ConfigFile config) { HostOnly = config.Bind("Access", "HostOnly", false, "When true only the host may open a private instance."); AllowVanillaMaps = config.Bind("Access", "AllowVanillaMaps", true, "When false only maps added by MapLoader may be instanced, leaving the vanilla world alone."); SleepIdleInstances = config.Bind("Performance", "SleepIdleInstances", true, "On the host, stops drawing props, lights, cameras and particles in instances you are not standing in."); SleepCreepVisuals = config.Bind("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 Claims = new List(); internal static IList 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 Pending = new List(); 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 Renderers = new List(); internal List Behaviours = new List(); internal List Particles = new List(); internal List Audio = new List(); internal List Animators = new List(); } internal static class InstanceSleeper { private static readonly List Slept = new List(); 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(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(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(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(true); foreach (ReflectionProbe val5 in componentsInChildren4) { if (((Behaviour)val5).enabled) { ((Behaviour)val5).enabled = false; sleptInstance.Behaviours.Add((Behaviour)(object)val5); } } ParticleSystem[] componentsInChildren5 = val.GetComponentsInChildren(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(true); foreach (AudioSource val7 in componentsInChildren6) { if (val7.isPlaying && !Skip(((Component)val7).transform, null)) { val7.Pause(); sleptInstance.Audio.Add(val7); } } Animator[] componentsInChildren7 = val.GetComponentsInChildren(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() != (Object)null) { return true; } if (TundrasInstancerConfig.SleepCreepVisuals.Value) { return false; } return (Object)(object)((Component)transform).GetComponentInParent() != (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 QueueHolds = new Dictionary(); 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 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(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(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 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 hashSet = new HashSet(); 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 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; } } }