Decompiled source of ArtifactOfParallel v1.0.1

ArtifactOfParallel.dll

Decompiled 17 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG;
using HG.Reflection;
using Microsoft.CodeAnalysis;
using MonoMod.RuntimeDetour;
using On.RoR2;
using On.RoR2.Projectile;
using On.RoR2.UI;
using R2API;
using R2API.Utils;
using RiskOfOptions;
using RiskOfOptions.Options;
using RoR2;
using RoR2.Hologram;
using RoR2.Projectile;
using RoR2.UI;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ArtifactOfParallel")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+20bf3827aba0faf20dbbe0d748a808e9db9ca520")]
[assembly: AssemblyProduct("ArtifactOfParallel")]
[assembly: AssemblyTitle("ArtifactOfParallel")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ArtifactOfParallel
{
	[BepInPlugin("kaitorque.ArtifactOfParallel", "ArtifactOfParallel", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class ArtifactOfParallelPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "kaitorque.ArtifactOfParallel";

		public const string PluginName = "ArtifactOfParallel";

		public const string PluginVersion = "1.0.1";

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			DebugLog.Init();
			ParallelArtifact.Register();
			PrivatePrefabs.Init();
			InteractionHooks.Init();
			SceneModelCleanup.Init();
			LootAssigner.Init();
			OwnershipTracker.Init();
			RiskOfOptionsCompat.TryInit();
		}

		private void FixedUpdate()
		{
			OwnershipTracker.FixedUpdate();
		}
	}
	internal static class DebugLog
	{
		private static readonly HashSet<string> logged = new HashSet<string>();

		public static bool Enabled => ModConfig.DebugLogging.Value;

		public static void Init()
		{
			Stage.onStageStartGlobal += delegate
			{
				logged.Clear();
			};
		}

		public static void Info(string message)
		{
			if (Enabled)
			{
				ArtifactOfParallelPlugin.Log.LogInfo((object)message);
			}
		}

		public static void Once(string key, string message)
		{
			if (Enabled && logged.Add(key))
			{
				ArtifactOfParallelPlugin.Log.LogInfo((object)message);
			}
		}
	}
	internal static class InteractionHooks
	{
		[StructLayout(LayoutKind.Sequential, Size = 1)]
		private readonly struct DrifterScope : IDisposable
		{
			public DrifterScope(CharacterBody body)
			{
				drifterActor = ParallelOwner.UserOf(body);
				hasDrifterActor = true;
			}

			public void Dispose()
			{
				drifterActor = null;
				hasDrifterActor = false;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static hook_GetInteractability <0>__PurchaseInteraction_GetInteractability;

			public static hook_OnInteractionBegin <1>__PurchaseInteraction_OnInteractionBegin;

			public static hook_AssignPassenger <2>__DrifterBagController_AssignPassenger;

			public static hook_TransmuteTargetObject <3>__TinkerProjectile_TransmuteTargetObject;

			public static hook_RebuildPing <4>__PingIndicator_RebuildPing;
		}

		private static Hook isTargetableHook;

		private static NetworkUser drifterActor;

		private static bool hasDrifterActor;

		private static readonly FieldInfo PingTargetRenderers = typeof(PingIndicator).GetField("pingTargetRenderers", BindingFlags.Instance | BindingFlags.NonPublic);

		public static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			object obj = <>O.<0>__PurchaseInteraction_GetInteractability;
			if (obj == null)
			{
				hook_GetInteractability val = PurchaseInteraction_GetInteractability;
				<>O.<0>__PurchaseInteraction_GetInteractability = val;
				obj = (object)val;
			}
			PurchaseInteraction.GetInteractability += (hook_GetInteractability)obj;
			object obj2 = <>O.<1>__PurchaseInteraction_OnInteractionBegin;
			if (obj2 == null)
			{
				hook_OnInteractionBegin val2 = PurchaseInteraction_OnInteractionBegin;
				<>O.<1>__PurchaseInteraction_OnInteractionBegin = val2;
				obj2 = (object)val2;
			}
			PurchaseInteraction.OnInteractionBegin += (hook_OnInteractionBegin)obj2;
			object obj3 = <>O.<2>__DrifterBagController_AssignPassenger;
			if (obj3 == null)
			{
				hook_AssignPassenger val3 = DrifterBagController_AssignPassenger;
				<>O.<2>__DrifterBagController_AssignPassenger = val3;
				obj3 = (object)val3;
			}
			DrifterBagController.AssignPassenger += (hook_AssignPassenger)obj3;
			object obj4 = <>O.<3>__TinkerProjectile_TransmuteTargetObject;
			if (obj4 == null)
			{
				hook_TransmuteTargetObject val4 = TinkerProjectile_TransmuteTargetObject;
				<>O.<3>__TinkerProjectile_TransmuteTargetObject = val4;
				obj4 = (object)val4;
			}
			TinkerProjectile.TransmuteTargetObject += (hook_TransmuteTargetObject)obj4;
			object obj5 = <>O.<4>__PingIndicator_RebuildPing;
			if (obj5 == null)
			{
				hook_RebuildPing val5 = PingIndicator_RebuildPing;
				<>O.<4>__PingIndicator_RebuildPing = val5;
				obj5 = (object)val5;
			}
			PingIndicator.RebuildPing += (hook_RebuildPing)obj5;
			isTargetableHook = new Hook((MethodBase)typeof(SpecialObjectAttributes).GetProperty("isTargetable").GetGetMethod(), (Delegate)new Func<Func<SpecialObjectAttributes, bool>, SpecialObjectAttributes, bool>(SpecialObjectAttributes_isTargetable));
		}

		private static Interactability PurchaseInteraction_GetInteractability(orig_GetInteractability orig, PurchaseInteraction self, Interactor activator)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			ParallelOwner parallelOwner = default(ParallelOwner);
			if (((Component)self).TryGetComponent<ParallelOwner>(ref parallelOwner))
			{
				if (!parallelOwner.CanBeUsedBy(activator))
				{
					if (DebugLog.Enabled)
					{
						DebugLog.Once($"deny:{((Object)self).GetInstanceID()}:{ActorName(activator)}", "Interact: refused " + ActorName(activator) + " on " + ((Object)self).name + " (owner " + parallelOwner.OwnerName() + ")");
					}
					return (Interactability)0;
				}
				if (parallelOwner.IsPrivate && Object.op_Implicit((Object)(object)activator) && activator.isRemoteOp && !self.allowRemoteOpInteraction)
				{
					if (DebugLog.Enabled)
					{
						DebugLog.Once($"remoteop:{((Object)self).GetInstanceID()}", "Interact: allowed " + ActorName(activator) + "'s Remote Operation drone on their own " + ((Object)self).name);
					}
					self.allowRemoteOpInteraction = true;
					try
					{
						return orig.Invoke(self, activator);
					}
					finally
					{
						self.allowRemoteOpInteraction = false;
					}
				}
			}
			return orig.Invoke(self, activator);
		}

		private static void PurchaseInteraction_OnInteractionBegin(orig_OnInteractionBegin orig, PurchaseInteraction self, Interactor activator)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			ParallelOwner parallelOwner = default(ParallelOwner);
			if (DebugLog.Enabled && ((Component)self).TryGetComponent<ParallelOwner>(ref parallelOwner))
			{
				DebugLog.Info("Interact: " + ActorName(activator) + ((Object.op_Implicit((Object)(object)activator) && activator.isRemoteOp) ? " (Remote Operation)" : "") + " " + string.Format("used {0} at {1} (owner {2}, {3})", ((Object)self).name, ((Component)self).transform.position, parallelOwner.OwnerName(), parallelOwner.IsPrivate ? "private" : "shared"));
			}
			orig.Invoke(self, activator);
		}

		private static string ActorName(Interactor activator)
		{
			NetworkUser val = ParallelOwner.UserOf(Object.op_Implicit((Object)(object)activator) ? ((Component)activator).GetComponent<CharacterBody>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				if (!Object.op_Implicit((Object)(object)activator))
				{
					return "nobody";
				}
				return ((Object)activator).name;
			}
			return val.userName;
		}

		private static void PingIndicator_RebuildPing(orig_RebuildPing orig, PingIndicator self)
		{
			orig.Invoke(self);
			ParallelOwner parallelOwner = (Object.op_Implicit((Object)(object)self.pingTarget) ? self.pingTarget.GetComponentInParent<ParallelOwner>() : null);
			if (Object.op_Implicit((Object)(object)parallelOwner) && parallelOwner.IsLocallyHidden && PingTargetRenderers.GetValue(self) is List<Renderer> list)
			{
				list.Clear();
				DebugLog.Info("Ping: removed the outline from hidden " + ((Object)parallelOwner).name + " (owner " + parallelOwner.OwnerName() + "); the marker stays");
			}
		}

		private static bool SpecialObjectAttributes_isTargetable(Func<SpecialObjectAttributes, bool> orig, SpecialObjectAttributes self)
		{
			bool flag = orig(self);
			ParallelOwner parallelOwner = default(ParallelOwner);
			if (!flag || !((Component)self).TryGetComponent<ParallelOwner>(ref parallelOwner) || !parallelOwner.IsPrivate)
			{
				return flag;
			}
			bool flag2 = (hasDrifterActor ? parallelOwner.CanBeUsedBy(drifterActor) : parallelOwner.IsVisibleToLocalPlayer());
			if (!flag2 && DebugLog.Enabled)
			{
				string text = ((!hasDrifterActor) ? "local player" : (Object.op_Implicit((Object)(object)drifterActor) ? drifterActor.userName : "unknown player"));
				DebugLog.Once($"drifter:{((Object)self).GetInstanceID()}:{text}:{hasDrifterActor}", "Drifter: " + ((Object)self).name + " (owner " + parallelOwner.OwnerName() + ") can't be grabbed or Tinkered by " + text + (hasDrifterActor ? " (server check)" : " (targeting on this game)"));
			}
			return flag2;
		}

		private static void DrifterBagController_AssignPassenger(orig_AssignPassenger orig, DrifterBagController self, GameObject passengerObject)
		{
			using (new DrifterScope(((Component)self).GetComponent<CharacterBody>()))
			{
				orig.Invoke(self, passengerObject);
			}
		}

		private static void TinkerProjectile_TransmuteTargetObject(orig_TransmuteTargetObject orig, TinkerProjectile self, GameObject targetObject)
		{
			ProjectileController val2 = default(ProjectileController);
			GameObject val = (((Component)self).TryGetComponent<ProjectileController>(ref val2) ? val2.owner : null);
			using (new DrifterScope(Object.op_Implicit((Object)(object)val) ? val.GetComponent<CharacterBody>() : null))
			{
				orig.Invoke(self, targetObject);
			}
		}
	}
	internal static class LootAssigner
	{
		private struct Spawned
		{
			public GameObject obj;

			public int value;
		}

		private struct Fixed
		{
			public GameObject obj;

			public InteractableSpawnCard card;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static Action<SceneDirector> <0>__OnPrePopulate;

			public static Action<SceneDirector, GameObject, DirectorCard> <1>__OnSpawnInteractable;

			public static Action<SceneDirector> <2>__OnPostPopulate;

			public static hook_TrySpawnObject <3>__DirectorCore_TrySpawnObject;
		}

		private static readonly List<Spawned> privateObjects = new List<Spawned>();

		private static readonly Dictionary<string, List<GameObject>> itemBoxes = new Dictionary<string, List<GameObject>>();

		private static readonly SortedDictionary<string, (int count, int value)> sharedCounts = new SortedDictionary<string, (int, int)>();

		private static readonly SortedDictionary<string, (int count, int value)> privateCounts = new SortedDictionary<string, (int, int)>();

		private static int sharedValue;

		private static bool populating;

		public static void Init()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			SceneDirector.onPrePopulateSceneServer += OnPrePopulate;
			SceneDirector.onSpawnInteractableServer += OnSpawnInteractable;
			SceneDirector.onPostPopulateSceneServer += OnPostPopulate;
			object obj = <>O.<3>__DirectorCore_TrySpawnObject;
			if (obj == null)
			{
				hook_TrySpawnObject val = DirectorCore_TrySpawnObject;
				<>O.<3>__DirectorCore_TrySpawnObject = val;
				obj = (object)val;
			}
			DirectorCore.TrySpawnObject += (hook_TrySpawnObject)obj;
		}

		private static void OnPrePopulate(SceneDirector director)
		{
			privateObjects.Clear();
			itemBoxes.Clear();
			sharedCounts.Clear();
			privateCounts.Clear();
			sharedValue = 0;
			populating = true;
		}

		private static void OnSpawnInteractable(SceneDirector director, GameObject obj, DirectorCard card)
		{
			if (!Object.op_Implicit((Object)(object)obj) || card == null)
			{
				return;
			}
			bool flag = PrivatePrefabs.IsPrivate(card.GetSpawnCard()) && Object.op_Implicit((Object)(object)obj.GetComponent<ParallelOwner>());
			if (DebugLog.Enabled)
			{
				CountSpawn((flag && ParallelArtifact.Enabled) ? privateCounts : sharedCounts, card);
			}
			if (ParallelArtifact.Enabled)
			{
				if (flag)
				{
					privateObjects.Add(new Spawned
					{
						obj = obj,
						value = card.cost
					});
				}
				else
				{
					sharedValue += card.cost;
				}
			}
		}

		private static GameObject DirectorCore_TrySpawnObject(orig_TrySpawnObject orig, DirectorCore self, DirectorSpawnRequest request)
		{
			GameObject val = orig.Invoke(self, request);
			if (populating && request != null && PrivatePrefabs.IsItemBox(request.spawnCard))
			{
				string name = ((Object)request.spawnCard).name;
				if (!itemBoxes.TryGetValue(name, out var value))
				{
					value = (itemBoxes[name] = new List<GameObject>());
				}
				value.Add(val);
			}
			return val;
		}

		private static void OnPostPopulate(SceneDirector director)
		{
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Expected O, but got Unknown
			populating = false;
			List<Spawned> list = privateObjects.Where((Spawned spawned) => Object.op_Implicit((Object)(object)spawned.obj)).ToList();
			privateObjects.Clear();
			LogSpawnCounts();
			if (!ParallelArtifact.Enabled)
			{
				return;
			}
			DebugLog.Info("Settings: " + ModConfig.Summary());
			List<NetworkUser> list2 = NetworkUser.readOnlyInstancesList.Where((NetworkUser user) => Object.op_Implicit((Object)(object)user) && Object.op_Implicit((Object)(object)user.master)).ToList();
			int num = list.Sum((Spawned spawned) => spawned.value);
			StringBuilder stringBuilder = new StringBuilder();
			object[] array = new object[4];
			SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef;
			array[0] = ((mostRecentSceneDef != null) ? mostRecentSceneDef.cachedName : null);
			array[1] = list2.Count;
			array[2] = sharedValue;
			array[3] = num;
			stringBuilder.Append(string.Format("Stage {0}: players={1} shared={2} private={3}", array));
			if (list2.Count <= 1)
			{
				Log(stringBuilder.Append(" (not split: fewer than 2 players)"));
				return;
			}
			Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.seed ^ (ulong)((Run.instance.stageClearCount + 1) * -7046029254386353131L));
			Shuffle(list2, rng);
			List<Fixed> list3 = FindFixedObjects();
			int num2 = list3.Sum((Fixed item) => ((SpawnCard)item.card).directorCreditCost);
			float num3 = (float)(num + num2) / (float)list2.Count;
			bool flag = list3.Count > 0 && (float)num2 <= num3;
			if (!flag)
			{
				num3 = (float)num / (float)list2.Count;
			}
			stringBuilder.Append(string.Format(" fixed={0} ({1} objects, {2})", num2, list3.Count, (list3.Count == 0) ? "none" : (flag ? "copied" : "shared")));
			stringBuilder.Append($" target={num3:0.#}");
			int[] array2 = new int[list2.Count];
			int[] array3 = new int[list2.Count];
			if (flag)
			{
				CopyFixedObjects(list3, list2);
				for (int num4 = 0; num4 < list2.Count; num4++)
				{
					array2[num4] = num2;
					array3[num4] = list3.Count;
				}
			}
			Shuffle(list, rng);
			list = list.OrderByDescending((Spawned spawned) => spawned.value).ToList();
			int num5 = 0;
			int num6 = 0;
			List<string>[] array4 = new List<string>[list2.Count];
			for (int num7 = 0; num7 < array4.Length; num7++)
			{
				array4[num7] = new List<string>();
			}
			List<string> list4 = new List<string>();
			foreach (Spawned item in list)
			{
				int num8 = 0;
				for (int num9 = 1; num9 < array2.Length; num9++)
				{
					if (array2[num9] < array2[num8])
					{
						num8 = num9;
					}
				}
				if ((float)(array2[num8] + item.value) <= num3 + (float)item.value * 0.5f)
				{
					item.obj.GetComponent<ParallelOwner>().SetOwner(list2[num8]);
					array2[num8] += item.value;
					array3[num8]++;
					array4[num8].Add(ShortName(item));
				}
				else
				{
					num5 += item.value;
					num6++;
					list4.Add(ShortName(item));
					NetworkServer.Destroy(item.obj);
				}
			}
			for (int num10 = 0; num10 < list2.Count; num10++)
			{
				stringBuilder.Append(string.Format("\n  {0}: value={1} objects={2} [{3}]", list2[num10].userName, array2[num10], array3[num10], string.Join(", ", array4[num10])));
			}
			stringBuilder.Append(string.Format("\n  removed: value={0} objects={1} [{2}]", num5, num6, string.Join(", ", list4)));
			AssignItemBoxes(stringBuilder);
			Log(stringBuilder);
		}

		private static List<Fixed> FindFixedObjects()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			List<Fixed> list = new List<Fixed>();
			PurchaseInteraction[] array = Object.FindObjectsOfType<PurchaseInteraction>();
			foreach (PurchaseInteraction val in array)
			{
				if (!val.available || Object.op_Implicit((Object)(object)((Component)val).GetComponent<ParallelOwner>()))
				{
					continue;
				}
				NetworkIdentity component = ((Component)val).GetComponent<NetworkIdentity>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					continue;
				}
				NetworkSceneId sceneId = component.sceneId;
				if (!((NetworkSceneId)(ref sceneId)).IsEmpty())
				{
					InteractableSpawnCard val2 = PrivatePrefabs.FindCardForSceneObject(val);
					if (Object.op_Implicit((Object)(object)val2))
					{
						list.Add(new Fixed
						{
							obj = ((Component)val).gameObject,
							card = val2
						});
					}
				}
			}
			return list;
		}

		private static void CopyFixedObjects(List<Fixed> fixedObjects, List<NetworkUser> players)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			foreach (Fixed fixedObject in fixedObjects)
			{
				Transform transform = fixedObject.obj.transform;
				foreach (NetworkUser player in players)
				{
					GameObject obj = Object.Instantiate<GameObject>(((SpawnCard)fixedObject.card).prefab, transform.position, transform.rotation);
					obj.GetComponent<ParallelOwner>().SetOwner(player);
					NetworkServer.Spawn(obj);
				}
				NetworkIdentity component = fixedObject.obj.GetComponent<NetworkIdentity>();
				if (Object.op_Implicit((Object)(object)component))
				{
					NetworkInstanceId netId = component.netId;
					if (!((NetworkInstanceId)(ref netId)).IsEmpty())
					{
						NetworkServer.Destroy(fixedObject.obj);
						continue;
					}
				}
				Object.Destroy((Object)(object)fixedObject.obj);
			}
		}

		private static void AssignItemBoxes(StringBuilder log)
		{
			if (ModConfig.PrivateItemBoxes.Value)
			{
				AssignItemBoxes(log, "iscLockbox", Items.TreasureCache);
				AssignItemBoxes(log, "iscLockboxVoid", Items.TreasureCacheVoid);
				AssignItemBoxes(log, "iscFreeChest", Items.FreeChest);
			}
		}

		private static void AssignItemBoxes(StringBuilder log, string cardName, ItemDef item)
		{
			if (!Object.op_Implicit((Object)(object)item) || !itemBoxes.TryGetValue(cardName, out var value))
			{
				return;
			}
			List<CharacterMaster> list = CharacterMaster.readOnlyInstancesList.Where((CharacterMaster master) => Object.op_Implicit((Object)(object)master.inventory) && master.inventory.GetItemCountEffective(item) > 0).ToList();
			ParallelOwner parallelOwner = default(ParallelOwner);
			for (int num = 0; num < value.Count; num++)
			{
				GameObject val = value[num];
				if (Object.op_Implicit((Object)(object)val) && val.TryGetComponent<ParallelOwner>(ref parallelOwner))
				{
					NetworkUser val2 = ((num < list.Count) ? PlayerFor(list[num]) : null);
					if (Object.op_Implicit((Object)(object)val2))
					{
						parallelOwner.SetOwner(val2);
					}
					log.Append("\n  " + cardName + ": " + (Object.op_Implicit((Object)(object)val2) ? val2.userName : "shared"));
				}
			}
		}

		private static NetworkUser PlayerFor(CharacterMaster master)
		{
			if (Object.op_Implicit((Object)(object)master.playerCharacterMasterController))
			{
				return master.playerCharacterMasterController.networkUser;
			}
			CharacterMaster val = (Object.op_Implicit((Object)(object)master.minionOwnership) ? master.minionOwnership.ownerMaster : null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.playerCharacterMasterController))
			{
				return null;
			}
			return val.playerCharacterMasterController.networkUser;
		}

		private static void Shuffle<T>(List<T> list, Xoroshiro128Plus rng)
		{
			for (int num = list.Count - 1; num > 0; num--)
			{
				int num2 = rng.RangeInt(0, num + 1);
				int index = num;
				int index2 = num2;
				T value = list[num2];
				T value2 = list[num];
				list[index] = value;
				list[index2] = value2;
			}
		}

		private static string ShortName(Spawned spawned)
		{
			return string.Format("{0} {1}", ((Object)spawned.obj).name.Replace("(Clone)", ""), spawned.value);
		}

		private static void CountSpawn(SortedDictionary<string, (int count, int value)> counts, DirectorCard card)
		{
			SpawnCard spawnCard = card.GetSpawnCard();
			string key = (Object.op_Implicit((Object)(object)spawnCard) ? ((Object)spawnCard).name : "unknown");
			counts.TryGetValue(key, out (int, int) value);
			counts[key] = (value.Item1 + 1, value.Item2 + card.cost);
		}

		private static void LogSpawnCounts()
		{
			if (DebugLog.Enabled)
			{
				StringBuilder stringBuilder = new StringBuilder();
				string[] obj = new string[6] { "Director spawns on ", null, null, null, null, null };
				SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef;
				obj[1] = ((mostRecentSceneDef != null) ? mostRecentSceneDef.cachedName : null);
				obj[2] = " (artifact ";
				obj[3] = (ParallelArtifact.Enabled ? "on" : "off");
				obj[4] = ", ";
				obj[5] = $"{NetworkUser.readOnlyInstancesList.Count((NetworkUser user) => Object.op_Implicit((Object)(object)user) && Object.op_Implicit((Object)(object)user.master))} players, before the split):";
				stringBuilder.Append(string.Concat(obj));
				AppendCounts(stringBuilder, "shared", sharedCounts);
				AppendCounts(stringBuilder, "private", privateCounts);
				DebugLog.Info(stringBuilder.ToString());
			}
		}

		private static void AppendCounts(StringBuilder log, string label, SortedDictionary<string, (int count, int value)> counts)
		{
			log.Append($"\n  {label}: {counts.Values.Sum(((int count, int value) entry) => entry.count)} objects, value {counts.Values.Sum(((int count, int value) entry) => entry.value)}");
			foreach (KeyValuePair<string, (int, int)> count in counts)
			{
				log.Append($"\n    {count.Key} x{count.Value.Item1} (value {count.Value.Item2})");
			}
		}

		private static void Log(StringBuilder text)
		{
			DebugLog.Info(text.ToString());
		}
	}
	internal static class ModConfig
	{
		public static ConfigEntry<bool> PrivateChests { get; private set; }

		public static ConfigEntry<bool> PrivateEquipmentBarrels { get; private set; }

		public static ConfigEntry<bool> PrivateLunarPods { get; private set; }

		public static ConfigEntry<bool> PrivateVoidCradles { get; private set; }

		public static ConfigEntry<bool> PrivateShrineOfChance { get; private set; }

		public static ConfigEntry<bool> PrivateMultishops { get; private set; }

		public static ConfigEntry<bool> PrivateItemBoxes { get; private set; }

		public static ConfigEntry<bool> DebugLogging { get; private set; }

		public static void Init(ConfigFile config)
		{
			PrivateChests = config.Bind<bool>("Private", "Chests", true, "Small, large, legendary, category and adaptive chests are split between players.");
			PrivateEquipmentBarrels = config.Bind<bool>("Private", "EquipmentBarrels", true, "Equipment barrels are split between players.");
			PrivateLunarPods = config.Bind<bool>("Private", "LunarPods", true, "Lunar pods are split between players.");
			PrivateVoidCradles = config.Bind<bool>("Private", "VoidCradles", true, "Void cradles and void potentials are split between players.");
			PrivateShrineOfChance = config.Bind<bool>("Private", "ShrineOfChance", true, "Shrines of Chance are split between players.");
			PrivateMultishops = config.Bind<bool>("Private", "Multishops", true, "Multishop terminals are split between players.");
			PrivateItemBoxes = config.Bind<bool>("Private", "ItemBoxes", true, "Rusted Key lockboxes, Encrusted Key caches and Shipping Request Form chests belong to the player whose item spawned them.");
			DebugLogging = config.Bind<bool>("Debug", "Logging", false, "Log each stage's loot split, ownership changes, and interaction, Drifter, ping and hiding checks. For testing.");
		}

		public static string Summary()
		{
			return $"Chests={PrivateChests.Value} EquipmentBarrels={PrivateEquipmentBarrels.Value} LunarPods={PrivateLunarPods.Value} " + $"VoidCradles={PrivateVoidCradles.Value} ShrineOfChance={PrivateShrineOfChance.Value} Multishops={PrivateMultishops.Value} " + $"ItemBoxes={PrivateItemBoxes.Value}";
		}
	}
	internal static class OwnershipTracker
	{
		private const float Interval = 0.25f;

		private const float DeathDelay = 1f;

		private static readonly HashSet<NetworkUserId> aliveThisStage = new HashSet<NetworkUserId>();

		private static readonly Dictionary<NetworkUserId, float> deadSince = new Dictionary<NetworkUserId, float>();

		private static readonly Dictionary<NetworkUserId, bool> lastShared = new Dictionary<NetworkUserId, bool>();

		private static readonly Dictionary<NetworkUserId, (NetworkUser user, bool shared)> states = new Dictionary<NetworkUserId, (NetworkUser, bool)>();

		private static readonly Dictionary<NetworkUserId, string> names = new Dictionary<NetworkUserId, string>();

		private static readonly List<ParallelOwner> buffer = new List<ParallelOwner>();

		private static float timer;

		public static void Init()
		{
			SceneDirector.onPrePopulateSceneServer += delegate
			{
				aliveThisStage.Clear();
				deadSince.Clear();
				lastShared.Clear();
			};
		}

		public static void FixedUpdate()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			timer -= Time.fixedDeltaTime;
			if (timer > 0f)
			{
				return;
			}
			timer = 0.25f;
			if (!NetworkServer.active || !ParallelArtifact.Enabled || ParallelOwner.Instances.Count == 0)
			{
				return;
			}
			states.Clear();
			buffer.Clear();
			buffer.AddRange(ParallelOwner.Instances);
			foreach (ParallelOwner item in buffer)
			{
				if (Object.op_Implicit((Object)(object)item) && item.HasOwner)
				{
					NetworkUserId ownerId = item.OwnerId;
					if (!states.TryGetValue(ownerId, out (NetworkUser, bool) value))
					{
						value = Evaluate(ownerId);
						states[ownerId] = value;
						LogChange(ownerId, value);
					}
					item.ServerUpdateState(value.Item1, value.Item2);
				}
			}
		}

		private static (NetworkUser user, bool shared) Evaluate(NetworkUserId id)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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)
			NetworkUser val = null;
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (Object.op_Implicit((Object)(object)readOnlyInstances))
				{
					NetworkUserId id2 = readOnlyInstances.id;
					if (((NetworkUserId)(ref id2)).Equals(id))
					{
						val = readOnlyInstances;
						break;
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				return (user: null, shared: true);
			}
			names[id] = val.userName;
			CharacterMaster master = val.master;
			CharacterBody val2 = (Object.op_Implicit((Object)(object)master) ? master.GetBody() : null);
			if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.healthComponent) && val2.healthComponent.alive)
			{
				aliveThisStage.Add(id);
				deadSince.Remove(id);
				return (user: val, shared: false);
			}
			if (!aliveThisStage.Contains(id))
			{
				return (user: val, shared: false);
			}
			if (!deadSince.TryGetValue(id, out var value))
			{
				value = (deadSince[id] = Time.time);
			}
			return (user: val, shared: Time.time - value >= 1f);
		}

		private static void LogChange(NetworkUserId id, (NetworkUser user, bool shared) state)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			if (!lastShared.TryGetValue(id, out var value) || value != state.shared)
			{
				lastShared[id] = state.shared;
				if (DebugLog.Enabled && (value || state.shared))
				{
					string value2;
					string text = (Object.op_Implicit((Object)(object)state.user) ? state.user.userName : (names.TryGetValue(id, out value2) ? value2 : "unknown player"));
					string text2 = ((!Object.op_Implicit((Object)(object)state.user)) ? "disconnected" : (state.shared ? "dead" : "back"));
					ArtifactOfParallelPlugin.Log.LogInfo((object)("Owner " + text + " " + text2 + ": objects now " + (state.shared ? "shared" : "private")));
				}
			}
		}
	}
	public static class ParallelApi
	{
		public static event Action<GameObject, bool> LocalVisibilityChanged;

		public static bool IsVisibleToLocalPlayer(GameObject obj)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return false;
			}
			ParallelOwner componentInParent = obj.GetComponentInParent<ParallelOwner>();
			if (Object.op_Implicit((Object)(object)componentInParent))
			{
				return !componentInParent.IsLocallyHidden;
			}
			return true;
		}

		internal static void RaiseLocalVisibilityChanged(GameObject obj, bool visible)
		{
			if (DebugLog.Enabled)
			{
				Action<GameObject, bool> localVisibilityChanged = ParallelApi.LocalVisibilityChanged;
				int num = ((localVisibilityChanged != null) ? localVisibilityChanged.GetInvocationList().Length : 0);
				DebugLog.Info(string.Format("ParallelApi: {0} visible={1}, {2} listeners", Object.op_Implicit((Object)(object)obj) ? ((Object)obj).name : "null", visible, num));
			}
			if (ParallelApi.LocalVisibilityChanged == null)
			{
				return;
			}
			try
			{
				ParallelApi.LocalVisibilityChanged(obj, visible);
			}
			catch (Exception arg)
			{
				ArtifactOfParallelPlugin.Log.LogError((object)$"ParallelApi.LocalVisibilityChanged handler failed: {arg}");
			}
		}
	}
	internal static class ParallelArtifact
	{
		private const string NameToken = "KAITORQUE_ARTIFACT_PARALLEL_NAME";

		private const string DescriptionToken = "KAITORQUE_ARTIFACT_PARALLEL_DESC";

		public static ArtifactDef Def { get; private set; }

		public static bool Enabled
		{
			get
			{
				if (Object.op_Implicit((Object)(object)Def) && Object.op_Implicit((Object)(object)RunArtifactManager.instance))
				{
					return RunArtifactManager.instance.IsArtifactEnabled(Def);
				}
				return false;
			}
		}

		public static void Register()
		{
			LanguageAPI.Add("KAITORQUE_ARTIFACT_PARALLEL_NAME", "Artifact of Parallel");
			LanguageAPI.Add("KAITORQUE_ARTIFACT_PARALLEL_DESC", "Chests, shrines and shops are split between players. You only see your own; anything that drops is shared. Total loot stays the same.");
			Def = ScriptableObject.CreateInstance<ArtifactDef>();
			Def.cachedName = "KaitorqueParallel";
			Def.nameToken = "KAITORQUE_ARTIFACT_PARALLEL_NAME";
			Def.descriptionToken = "KAITORQUE_ARTIFACT_PARALLEL_DESC";
			Def.smallIconSelectedSprite = LoadSprite("texArtifactParallelEnabled.png");
			Def.smallIconDeselectedSprite = LoadSprite("texArtifactParallelDisabled.png");
			if (!ContentAddition.AddArtifactDef(Def))
			{
				ArtifactOfParallelPlugin.Log.LogError((object)"Failed to register the artifact.");
			}
		}

		private static Sprite LoadSprite(string fileName)
		{
			//IL_0054: 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)
			//IL_0061: Expected O, but got Unknown
			//IL_0082: 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)
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ArtifactOfParallel." + fileName);
			if (stream == null)
			{
				ArtifactOfParallelPlugin.Log.LogError((object)("Missing embedded icon " + fileName + "."));
				return null;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
			{
				wrapMode = (TextureWrapMode)1
			};
			ImageConversion.LoadImage(val, array);
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}
	}
	public class ParallelOwner : NetworkBehaviour
	{
		private const uint OwnerDirtyBit = 1u;

		private NetworkUserId ownerId;

		private bool hasOwner;

		private NetworkInstanceId ownerNetId = NetworkInstanceId.Invalid;

		private bool isPrivate;

		private const float RescanInterval = 0.25f;

		private readonly HashSet<Behaviour> hiddenBehaviours = new HashSet<Behaviour>();

		private readonly HashSet<Renderer> hiddenRenderers = new HashSet<Renderer>();

		private readonly HashSet<Collider> hiddenColliders = new HashSet<Collider>();

		private bool locallyHidden;

		private float rescanTimer;

		private static readonly List<ParallelOwner> instances = new List<ParallelOwner>();

		public static IReadOnlyList<ParallelOwner> Instances => instances;

		public bool IsPrivate => isPrivate;

		public bool HasOwner => hasOwner;

		public NetworkUserId OwnerId => ownerId;

		public NetworkInstanceId OwnerNetId => ownerNetId;

		private static bool IsMidStage
		{
			get
			{
				//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.op_Implicit((Object)(object)Run.instance) && Object.op_Implicit((Object)(object)Stage.instance))
				{
					FixedTimeStamp entryTime = Stage.instance.entryTime;
					return ((FixedTimeStamp)(ref entryTime)).timeSince > 2f;
				}
				return false;
			}
		}

		public bool IsLocallyHidden => locallyHidden;

		private void OnEnable()
		{
			instances.Add(this);
		}

		private void OnDisable()
		{
			instances.Remove(this);
		}

		public unsafe void SetOwner(NetworkUser owner)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			hasOwner = Object.op_Implicit((Object)(object)owner);
			ownerId = (NetworkUserId)(Object.op_Implicit((Object)(object)owner) ? owner.id : default(NetworkUserId));
			ApplyState(hasOwner, Object.op_Implicit((Object)(object)owner) ? ((NetworkBehaviour)owner).netId : NetworkInstanceId.Invalid);
			MultiShopController val = default(MultiShopController);
			if (!((Component)this).TryGetComponent<MultiShopController>(ref val))
			{
				return;
			}
			ReadOnlyArray<GameObject> terminalGameObjectsList = val.terminalGameObjectsList;
			ParallelOwner parallelOwner = default(ParallelOwner);
			for (int i = 0; i < terminalGameObjectsList.Length; i++)
			{
				if (Object.op_Implicit((Object)Unsafe.Read<object>((void*)terminalGameObjectsList[i])) && ((GameObject)Unsafe.Read<object>((void*)terminalGameObjectsList[i])).TryGetComponent<ParallelOwner>(ref parallelOwner))
				{
					parallelOwner.SetOwner(owner);
				}
			}
		}

		public void ServerUpdateState(NetworkUser currentOwner, bool shared)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			if (hasOwner && !IsUsed())
			{
				bool flag = !shared && Object.op_Implicit((Object)(object)currentOwner);
				NetworkInstanceId val = (Object.op_Implicit((Object)(object)currentOwner) ? ((NetworkBehaviour)currentOwner).netId : NetworkInstanceId.Invalid);
				if (flag != isPrivate || val != ownerNetId)
				{
					ApplyState(flag, val);
				}
			}
		}

		private void ApplyState(bool newPrivate, NetworkInstanceId newOwnerNetId)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			isPrivate = newPrivate;
			ownerNetId = newOwnerNetId;
			if (((NetworkBehaviour)this).isServer)
			{
				((NetworkBehaviour)this).SetDirtyBit(1u);
				((Component)this).GetComponent<NetworkIdentity>().RebuildObservers(false);
			}
			RefreshLocalVisibility();
		}

		private unsafe bool IsUsed()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			PurchaseInteraction val = default(PurchaseInteraction);
			if (((Component)this).TryGetComponent<PurchaseInteraction>(ref val))
			{
				return !val.available;
			}
			MultiShopController val2 = default(MultiShopController);
			if (((Component)this).TryGetComponent<MultiShopController>(ref val2))
			{
				ReadOnlyArray<GameObject> terminalGameObjectsList = val2.terminalGameObjectsList;
				PurchaseInteraction val3 = default(PurchaseInteraction);
				for (int i = 0; i < terminalGameObjectsList.Length; i++)
				{
					if (Object.op_Implicit((Object)Unsafe.Read<object>((void*)terminalGameObjectsList[i])) && ((GameObject)Unsafe.Read<object>((void*)terminalGameObjectsList[i])).TryGetComponent<PurchaseInteraction>(ref val3) && val3.available)
					{
						return false;
					}
				}
				return terminalGameObjectsList.Length > 0;
			}
			return false;
		}

		public bool IsOwnedBy(NetworkUser user)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)user))
			{
				return false;
			}
			if (!NetworkServer.active)
			{
				return ((NetworkBehaviour)user).netId == ownerNetId;
			}
			if (hasOwner)
			{
				NetworkUserId id = user.id;
				return ((NetworkUserId)(ref id)).Equals(ownerId);
			}
			return false;
		}

		public bool CanBeUsedBy(Interactor activator)
		{
			return CanBeUsedBy(UserOf(Object.op_Implicit((Object)(object)activator) ? ((Component)activator).GetComponent<CharacterBody>() : null));
		}

		public bool CanBeUsedBy(NetworkUser user)
		{
			if (isPrivate)
			{
				return IsOwnedBy(user);
			}
			return true;
		}

		public static NetworkUser UserOf(CharacterBody body)
		{
			CharacterMaster val = (Object.op_Implicit((Object)(object)body) ? body.master : null);
			PlayerCharacterMasterController val2 = (Object.op_Implicit((Object)(object)val) ? val.playerCharacterMasterController : null);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return null;
			}
			return val2.networkUser;
		}

		public bool IsVisibleToLocalPlayer()
		{
			if (!isPrivate)
			{
				return true;
			}
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				if (IsOwnedBy(readOnlyLocalPlayers))
				{
					return true;
				}
			}
			return false;
		}

		public string OwnerName()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (IsOwnedBy(readOnlyInstances))
				{
					return readOnlyInstances.userName;
				}
			}
			if (!hasOwner && !(ownerNetId != NetworkInstanceId.Invalid))
			{
				return "none";
			}
			return "absent player";
		}

		public string Describe()
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			string text = OwnerName();
			int num = 0;
			Renderer[] array = Parts<Renderer>(includeInactive: false);
			foreach (Renderer val in array)
			{
				if (val.enabled && !val.forceRenderingOff)
				{
					num++;
				}
			}
			NetworkIdentity component = ((Component)this).GetComponent<NetworkIdentity>();
			string text2 = ((NetworkServer.active && Object.op_Implicit((Object)(object)component) && component.observers != null) ? component.observers.Count.ToString() : "-");
			return $"{((Object)this).name} netId={((NetworkBehaviour)this).netId} private={isPrivate} owner={text} ownerNetId={ownerNetId} " + $"visibleToLocal={IsVisibleToLocalPlayer()} hidden={locallyHidden} renderersOn={num} observers={text2} pos={((Component)this).transform.position}";
		}

		public override bool OnCheckObserver(NetworkConnection conn)
		{
			if (isPrivate)
			{
				return IsOwnerConnection(conn);
			}
			return true;
		}

		public override bool OnRebuildObservers(HashSet<NetworkConnection> observers, bool initialize)
		{
			AddObservers(NetworkServer.connections, observers);
			AddObservers(NetworkServer.localConnections, observers);
			return true;
		}

		public override void OnSetLocalVisibility(bool vis)
		{
			RefreshLocalVisibility();
		}

		private void AddObservers(IList<NetworkConnection> connections, HashSet<NetworkConnection> observers)
		{
			foreach (NetworkConnection connection in connections)
			{
				if (connection != null && connection.isReady && ((NetworkBehaviour)this).OnCheckObserver(connection))
				{
					observers.Add(connection);
				}
			}
		}

		private bool IsOwnerConnection(NetworkConnection conn)
		{
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (((NetworkBehaviour)readOnlyInstances).connectionToClient == conn && IsOwnedBy(readOnlyInstances))
				{
					return true;
				}
			}
			return false;
		}

		private void Start()
		{
			RefreshLocalVisibility();
		}

		public void RefreshLocalVisibility()
		{
			bool flag = NetworkUser.readOnlyLocalPlayersList.Count > 0 && !IsVisibleToLocalPlayer();
			if (flag == locallyHidden)
			{
				return;
			}
			locallyHidden = flag;
			if (DebugLog.Enabled)
			{
				DebugLog.Info("Visibility: " + ((Object)this).name + " (owner " + OwnerName() + ") is now " + (flag ? "hidden" : "visible") + " here");
			}
			if (flag)
			{
				Hide();
			}
			else
			{
				Show();
			}
			PingIndicator[] array = PingIndicator.instancesList.ToArray();
			foreach (PingIndicator val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.pingTarget) && (Object)(object)val.pingTarget.GetComponentInParent<ParallelOwner>() == (Object)(object)this)
				{
					val.RebuildPing();
				}
			}
			ParallelApi.RaiseLocalVisibilityChanged(((Component)this).gameObject, !flag);
		}

		public override void OnStartClient()
		{
			if (!NetworkServer.active && IsMidStage)
			{
				ParallelApi.RaiseLocalVisibilityChanged(((Component)this).gameObject, visible: true);
			}
		}

		public override void OnNetworkDestroy()
		{
			if (!NetworkServer.active && IsMidStage)
			{
				ParallelApi.RaiseLocalVisibilityChanged(((Component)this).gameObject, visible: false);
			}
		}

		private void LateUpdate()
		{
			if (!locallyHidden)
			{
				return;
			}
			rescanTimer -= Time.deltaTime;
			if (rescanTimer <= 0f)
			{
				rescanTimer = 0.25f;
				Hide();
			}
			int num = 0;
			foreach (Renderer hiddenRenderer in hiddenRenderers)
			{
				if (Object.op_Implicit((Object)(object)hiddenRenderer) && !hiddenRenderer.forceRenderingOff)
				{
					hiddenRenderer.forceRenderingOff = true;
					num++;
				}
			}
			foreach (Collider hiddenCollider in hiddenColliders)
			{
				if (Object.op_Implicit((Object)(object)hiddenCollider) && hiddenCollider.enabled)
				{
					hiddenCollider.enabled = false;
					num++;
				}
			}
			foreach (Behaviour hiddenBehaviour in hiddenBehaviours)
			{
				if (Object.op_Implicit((Object)(object)hiddenBehaviour) && hiddenBehaviour.enabled)
				{
					hiddenBehaviour.enabled = false;
					num++;
					HologramProjector val = (HologramProjector)(object)((hiddenBehaviour is HologramProjector) ? hiddenBehaviour : null);
					if (val != null && Object.op_Implicit((Object)(object)val.hologramContentInstance))
					{
						Object.Destroy((Object)(object)val.hologramContentInstance);
						val.hologramContentInstance = null;
					}
				}
			}
			if (num > 0 && DebugLog.Enabled)
			{
				DebugLog.Once("rehide:" + ((Object)this).GetInstanceID(), $"Hiding: {((Object)this).name} (owner {OwnerName()}) had {num} hidden parts switched back on (e.g. Drifter grab or throw); hid them again.");
			}
		}

		private T[] Parts<T>(bool includeInactive = false) where T : Component
		{
			T[] componentsInChildren = ((Component)this).GetComponentsInChildren<T>(includeInactive);
			ModelLocator component = ((Component)this).GetComponent<ModelLocator>();
			Transform val = (Object.op_Implicit((Object)(object)component) ? component.modelTransform : null);
			if (!Object.op_Implicit((Object)(object)val) || val.IsChildOf(((Component)this).transform))
			{
				return componentsInChildren;
			}
			T[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<T>(includeInactive);
			if (componentsInChildren2.Length == 0)
			{
				return componentsInChildren;
			}
			T[] array = new T[componentsInChildren.Length + componentsInChildren2.Length];
			componentsInChildren.CopyTo(array, 0);
			componentsInChildren2.CopyTo(array, componentsInChildren.Length);
			return array;
		}

		private void Hide()
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			Renderer[] array = Parts<Renderer>(includeInactive: true);
			foreach (Renderer val in array)
			{
				if (hiddenRenderers.Add(val))
				{
					val.forceRenderingOff = true;
					num++;
				}
			}
			Collider[] array2 = Parts<Collider>(includeInactive: false);
			foreach (Collider val2 in array2)
			{
				if (val2.enabled && hiddenColliders.Add(val2))
				{
					val2.enabled = false;
					num2++;
				}
			}
			Light[] array3 = Parts<Light>(includeInactive: false);
			foreach (Light val3 in array3)
			{
				if (((Behaviour)val3).enabled)
				{
					hiddenBehaviours.Add((Behaviour)(object)val3);
					((Behaviour)val3).enabled = false;
					num3++;
				}
			}
			Highlight[] array4 = Parts<Highlight>(includeInactive: false);
			foreach (Highlight val4 in array4)
			{
				val4.isOn = false;
				if (((Behaviour)val4).enabled && hiddenBehaviours.Add((Behaviour)(object)val4))
				{
					((Behaviour)val4).enabled = false;
				}
			}
			HologramProjector[] array5 = Parts<HologramProjector>(includeInactive: false);
			foreach (HologramProjector val5 in array5)
			{
				if (Object.op_Implicit((Object)(object)val5.hologramContentInstance))
				{
					Object.Destroy((Object)(object)val5.hologramContentInstance);
					val5.hologramContentInstance = null;
					num4++;
				}
				if (((Behaviour)val5).enabled && hiddenBehaviours.Add((Behaviour)(object)val5))
				{
					((Behaviour)val5).enabled = false;
				}
			}
			if (num + num2 + num3 + num4 > 0 && DebugLog.Enabled)
			{
				DebugLog.Info($"Hiding: {((Object)this).name} (owner {OwnerName()}) renderers+{num} colliders+{num2} lights+{num3} priceLabels+{num4}");
			}
		}

		private void Show()
		{
			foreach (Renderer hiddenRenderer in hiddenRenderers)
			{
				if (Object.op_Implicit((Object)(object)hiddenRenderer))
				{
					hiddenRenderer.forceRenderingOff = false;
				}
			}
			foreach (Collider hiddenCollider in hiddenColliders)
			{
				if (Object.op_Implicit((Object)(object)hiddenCollider))
				{
					hiddenCollider.enabled = true;
				}
			}
			foreach (Behaviour hiddenBehaviour in hiddenBehaviours)
			{
				if (Object.op_Implicit((Object)(object)hiddenBehaviour))
				{
					hiddenBehaviour.enabled = true;
				}
			}
			hiddenRenderers.Clear();
			hiddenColliders.Clear();
			hiddenBehaviours.Clear();
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			if (initialState)
			{
				WriteState(writer);
				return true;
			}
			uint syncVarDirtyBits = ((NetworkBehaviour)this).syncVarDirtyBits;
			writer.WritePackedUInt32(syncVarDirtyBits);
			if (syncVarDirtyBits != 0)
			{
				WriteState(writer);
			}
			return syncVarDirtyBits != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (initialState || reader.ReadPackedUInt32() != 0)
			{
				ownerNetId = reader.ReadNetworkId();
				isPrivate = reader.ReadBoolean();
				RefreshLocalVisibility();
			}
		}

		private void WriteState(NetworkWriter writer)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			writer.Write(ownerNetId);
			writer.Write(isPrivate);
		}
	}
	internal enum PrivateType
	{
		Chest,
		EquipmentBarrel,
		LunarPod,
		VoidCradle,
		ShrineOfChance,
		Multishop,
		ItemBox
	}
	internal static class PrivatePrefabs
	{
		public const string SmallChest = "RoR2/Base/Chest1/iscChest1.asset";

		private static readonly (string key, PrivateType type)[] SpawnCards = new(string, PrivateType)[25]
		{
			("RoR2/Base/Chest1/iscChest1.asset", PrivateType.Chest),
			("RoR2/Base/Chest1StealthedVariant/iscChest1Stealthed.asset", PrivateType.Chest),
			("RoR2/Base/Chest2/iscChest2.asset", PrivateType.Chest),
			("RoR2/Base/GoldChest/iscGoldChest.asset", PrivateType.Chest),
			("RoR2/Base/CategoryChest/iscCategoryChestDamage.asset", PrivateType.Chest),
			("RoR2/Base/CategoryChest/iscCategoryChestHealing.asset", PrivateType.Chest),
			("RoR2/Base/CategoryChest/iscCategoryChestUtility.asset", PrivateType.Chest),
			("RoR2/DLC1/CategoryChest2/iscCategoryChest2Damage.asset", PrivateType.Chest),
			("RoR2/DLC1/CategoryChest2/iscCategoryChest2Healing.asset", PrivateType.Chest),
			("RoR2/DLC1/CategoryChest2/iscCategoryChest2Utility.asset", PrivateType.Chest),
			("RoR2/Base/CasinoChest/iscCasinoChest.asset", PrivateType.Chest),
			("RoR2/Base/EquipmentBarrel/iscEquipmentBarrel.asset", PrivateType.EquipmentBarrel),
			("RoR2/Base/LunarChest/iscLunarChest.asset", PrivateType.LunarPod),
			("RoR2/DLC1/VoidChest/iscVoidChest.asset", PrivateType.VoidCradle),
			("RoR2/DLC1/VoidChest/iscVoidChestSacrificeOn.asset", PrivateType.VoidCradle),
			("RoR2/DLC1/VoidTriple/iscVoidTriple.asset", PrivateType.VoidCradle),
			("RoR2/Base/ShrineChance/iscShrineChance.asset", PrivateType.ShrineOfChance),
			("RoR2/Base/ShrineChance/iscShrineChanceSandy.asset", PrivateType.ShrineOfChance),
			("RoR2/Base/ShrineChance/iscShrineChanceSnowy.asset", PrivateType.ShrineOfChance),
			("RoR2/Base/TripleShop/iscTripleShop.asset", PrivateType.Multishop),
			("RoR2/Base/TripleShopLarge/iscTripleShopLarge.asset", PrivateType.Multishop),
			("RoR2/Base/TripleShopEquipment/iscTripleShopEquipment.asset", PrivateType.Multishop),
			("RoR2/Junk/TreasureCache/iscLockbox.asset", PrivateType.ItemBox),
			("RoR2/DLC1/TreasureCacheVoid/iscLockboxVoid.asset", PrivateType.ItemBox),
			("RoR2/DLC1/FreeChest/iscFreeChest.asset", PrivateType.ItemBox)
		};

		private static readonly Dictionary<SpawnCard, PrivateType> typeByCard = new Dictionary<SpawnCard, PrivateType>();

		private static readonly Dictionary<string, InteractableSpawnCard> cardByNameToken = new Dictionary<string, InteractableSpawnCard>();

		public static void Init()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			(string, PrivateType)[] spawnCards = SpawnCards;
			MultiShopController val2 = default(MultiShopController);
			PurchaseInteraction val3 = default(PurchaseInteraction);
			for (int i = 0; i < spawnCards.Length; i++)
			{
				(string, PrivateType) tuple = spawnCards[i];
				string item = tuple.Item1;
				PrivateType item2 = tuple.Item2;
				InteractableSpawnCard val = Addressables.LoadAssetAsync<InteractableSpawnCard>((object)item).WaitForCompletion();
				if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((SpawnCard)val).prefab))
				{
					ArtifactOfParallelPlugin.Log.LogError((object)("Spawn card " + item + " not found."));
					continue;
				}
				AddOwner(((SpawnCard)val).prefab);
				if (((SpawnCard)val).prefab.TryGetComponent<MultiShopController>(ref val2) && Object.op_Implicit((Object)(object)val2.terminalPrefab))
				{
					AddOwner(val2.terminalPrefab);
				}
				typeByCard[(SpawnCard)(object)val] = item2;
				if (item2 != PrivateType.ItemBox && ((SpawnCard)val).prefab.TryGetComponent<PurchaseInteraction>(ref val3) && !string.IsNullOrEmpty(val3.displayNameToken) && !cardByNameToken.ContainsKey(val3.displayNameToken))
				{
					cardByNameToken[val3.displayNameToken] = val;
				}
			}
		}

		private static void AddOwner(GameObject prefab)
		{
			if (!Object.op_Implicit((Object)(object)prefab.GetComponent<ParallelOwner>()))
			{
				prefab.AddComponent<ParallelOwner>();
			}
		}

		public static InteractableSpawnCard Load(string key)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Addressables.LoadAssetAsync<InteractableSpawnCard>((object)key).WaitForCompletion();
		}

		public static bool IsPrivate(SpawnCard card)
		{
			if (Object.op_Implicit((Object)(object)card) && typeByCard.TryGetValue(card, out var value))
			{
				return IsEnabled(value);
			}
			return false;
		}

		public static bool IsItemBox(SpawnCard card)
		{
			if (Object.op_Implicit((Object)(object)card) && typeByCard.TryGetValue(card, out var value))
			{
				return value == PrivateType.ItemBox;
			}
			return false;
		}

		public static InteractableSpawnCard FindCardForSceneObject(PurchaseInteraction purchase)
		{
			if (Object.op_Implicit((Object)(object)purchase) && !string.IsNullOrEmpty(purchase.displayNameToken) && cardByNameToken.TryGetValue(purchase.displayNameToken, out var value) && IsPrivate((SpawnCard)(object)value))
			{
				return value;
			}
			return null;
		}

		public static bool IsPrivateType(PurchaseInteraction purchase)
		{
			if (Object.op_Implicit((Object)(object)purchase) && !string.IsNullOrEmpty(purchase.displayNameToken))
			{
				return cardByNameToken.ContainsKey(purchase.displayNameToken);
			}
			return false;
		}

		private static bool IsEnabled(PrivateType type)
		{
			return ((ConfigEntry<bool>)(type switch
			{
				PrivateType.Chest => ModConfig.PrivateChests, 
				PrivateType.EquipmentBarrel => ModConfig.PrivateEquipmentBarrels, 
				PrivateType.LunarPod => ModConfig.PrivateLunarPods, 
				PrivateType.VoidCradle => ModConfig.PrivateVoidCradles, 
				PrivateType.ShrineOfChance => ModConfig.PrivateShrineOfChance, 
				PrivateType.Multishop => ModConfig.PrivateMultishops, 
				PrivateType.ItemBox => ModConfig.PrivateItemBoxes, 
				_ => null, 
			}))?.Value ?? false;
		}
	}
	internal static class RiskOfOptionsCompat
	{
		public const string Guid = "com.rune580.riskofoptions";

		public static void TryInit()
		{
			if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
			{
				Init();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static void Init()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			ModSettingsManager.SetModDescription("Splits chests, shrines and shops between players. The host's settings apply, read at the start of each stage.");
			if (Object.op_Implicit((Object)(object)ParallelArtifact.Def) && Object.op_Implicit((Object)(object)ParallelArtifact.Def.smallIconSelectedSprite))
			{
				ModSettingsManager.SetModIcon(ParallelArtifact.Def.smallIconSelectedSprite);
			}
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.PrivateChests));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.PrivateEquipmentBarrels));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.PrivateLunarPods));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.PrivateVoidCradles));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.PrivateShrineOfChance));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.PrivateMultishops));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.PrivateItemBoxes));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModConfig.DebugLogging));
			DebugLog.Info("Risk Of Options settings page added.");
		}
	}
	internal static class SceneModelCleanup
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_Start <0>__ModelLocator_Start;
		}

		public static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__ModelLocator_Start;
			if (obj == null)
			{
				hook_Start val = ModelLocator_Start;
				<>O.<0>__ModelLocator_Start = val;
				obj = (object)val;
			}
			ModelLocator.Start += (hook_Start)obj;
		}

		private static void ModelLocator_Start(orig_Start orig, ModelLocator self)
		{
			//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)
			orig.Invoke(self);
			if (NetworkServer.active || !ParallelArtifact.Enabled)
			{
				return;
			}
			Transform modelTransform = self.modelTransform;
			NetworkIdentity val = default(NetworkIdentity);
			if (Object.op_Implicit((Object)(object)modelTransform) && !modelTransform.IsChildOf(((Component)self).transform) && ((Component)self).TryGetComponent<NetworkIdentity>(ref val))
			{
				NetworkSceneId sceneId = val.sceneId;
				PurchaseInteraction purchase = default(PurchaseInteraction);
				if (!((NetworkSceneId)(ref sceneId)).IsEmpty() && ((Component)self).TryGetComponent<PurchaseInteraction>(ref purchase) && PrivatePrefabs.IsPrivateType(purchase))
				{
					((Component)self).gameObject.AddComponent<DetachedModelFollower>().model = ((Component)modelTransform).gameObject;
				}
			}
		}
	}
	internal class DetachedModelFollower : MonoBehaviour
	{
		public GameObject model;

		private void OnEnable()
		{
			if (Object.op_Implicit((Object)(object)model))
			{
				model.SetActive(true);
			}
		}

		private void OnDisable()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)model))
			{
				Scene scene = ((Component)this).gameObject.scene;
				if (((Scene)(ref scene)).isLoaded)
				{
					model.SetActive(false);
					DebugLog.Info($"Scene object: hid the leftover model of removed {((Object)this).name} at {((Component)this).transform.position}");
				}
			}
		}
	}
	internal static class TestCommands
	{
		private const float Spacing = 3f;

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void SpawnTestChests(ConCommandArgs args)
		{
			//IL_007f: 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_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_008e: 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_0097: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody senderBody = ((ConCommandArgs)(ref args)).senderBody;
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)senderBody))
			{
				Debug.Log((object)"parallel_test_chests: needs a living character on the host's run.");
				return;
			}
			InteractableSpawnCard val = PrivatePrefabs.Load("RoR2/Base/Chest1/iscChest1.asset");
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((SpawnCard)val).prefab) || !Object.op_Implicit((Object)(object)((SpawnCard)val).prefab.GetComponent<ParallelOwner>()))
			{
				Debug.Log((object)"parallel_test_chests: small chest spawn card failed to load; see the startup log.");
				return;
			}
			Vector3 val2 = Vector3.ProjectOnPlane(Object.op_Implicit((Object)(object)senderBody.inputBank) ? senderBody.inputBank.aimDirection : ((Component)senderBody).transform.forward, Vector3.up);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			Vector3 val3 = Vector3.Cross(Vector3.up, normalized);
			Vector3 val4 = senderBody.footPosition + normalized * 6f;
			Quaternion val5 = Quaternion.LookRotation(-normalized, Vector3.up);
			int num = 0;
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (Object.op_Implicit((Object)(object)readOnlyInstances.master))
				{
					num++;
				}
			}
			int num2 = 0;
			RaycastHit val8 = default(RaycastHit);
			foreach (NetworkUser readOnlyInstances2 in NetworkUser.readOnlyInstancesList)
			{
				if (Object.op_Implicit((Object)(object)readOnlyInstances2.master))
				{
					Vector3 val6 = val4 + val3 * (((float)num2 - (float)(num - 1) * 0.5f) * 3f);
					Vector3 val7 = val6 + Vector3.up * 5f;
					Vector3 down = Vector3.down;
					LayerIndex world = LayerIndex.world;
					if (Physics.Raycast(val7, down, ref val8, 20f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask)))
					{
						val6 = ((RaycastHit)(ref val8)).point;
					}
					GameObject obj = Object.Instantiate<GameObject>(((SpawnCard)val).prefab, val6, val5);
					obj.GetComponent<ParallelOwner>().SetOwner(readOnlyInstances2);
					NetworkServer.Spawn(obj);
					num2++;
					ArtifactOfParallelPlugin.Log.LogInfo((object)$"Test chest for {readOnlyInstances2.userName} at {val6}");
				}
			}
			Debug.Log((object)$"parallel_test_chests: spawned {num2} chests.");
		}

		[ConCommand(commandName = "parallel_debug", helpText = "Lists the private objects that exist on this game, their owner and whether they're hidden here.")]
		private static void DebugList(ConCommandArgs args)
		{
			ParallelOwner[] array = Object.FindObjectsOfType<ParallelOwner>();
			ArtifactOfParallelPlugin.Log.LogInfo((object)$"parallel_debug: server={NetworkServer.active} client={NetworkClient.active} objects={array.Length}");
			ParallelOwner[] array2 = array;
			foreach (ParallelOwner parallelOwner in array2)
			{
				ArtifactOfParallelPlugin.Log.LogInfo((object)("  " + parallelOwner.Describe()));
			}
			Debug.Log((object)$"parallel_debug: {array.Length} private-type objects here; details in the BepInEx log.");
		}
	}
}