Decompiled source of InstancedLoot continuation v1.3.0
InstancedLoot/InstancedLoot.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates.ScavBackpack; using EntityStates.Scrapper; using HG; using IL.EntityStates.ScavBackpack; using IL.EntityStates.Scrapper; using IL.RoR2; using IL.RoR2.Artifacts; using IL.RoR2.Hologram; using IL.RoR2.UI; using InstancedLoot.Components; using InstancedLoot.Configuration; using InstancedLoot.Configuration.Attributes; using InstancedLoot.Enums; using InstancedLoot.Hooks; using InstancedLoot.Networking; using InstancedLoot.ObjectHandlers; using Microsoft.CodeAnalysis; using Mono.Cecil.Cil; using MonoMod.Cil; using MonoMod.RuntimeDetour; using MonoMod.RuntimeDetour.HookGen; using On.RoR2; using On.RoR2.Artifacts; using On.RoR2.Hologram; using On.RoR2.Networking; using R2API.Networking; using R2API.Networking.Interfaces; using R2API.Utils; using RoR2; using RoR2.DirectionalSearch; using RoR2.Hologram; using RoR2.Networking; using RoR2.UI; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("KubeRoot")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("3.0.0.0")] [assembly: AssemblyInformationalVersion("3.0.0+74561ec7f28ada2fb287cb8b93701cc5879df795")] [assembly: AssemblyProduct("InstancedLoot")] [assembly: AssemblyTitle("InstancedLoot")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 InstancedLoot { public abstract class AbstractObjectHandler { public struct AwaitedObjectInfo { public GameObject SourceObject; public PlayerCharacterMasterController[] Players; public object ExtraInfo; } private static Dictionary<string, SpawnCard> _SpawnCardsForPrefabName; protected ObjectHandlerManager Manager; public readonly Dictionary<GameObject, AwaitedObjectInfo> InfoForAwaitedObjects = new Dictionary<GameObject, AwaitedObjectInfo>(); public static Dictionary<string, SpawnCard> SpawnCardsForPrefabName { get { if (_SpawnCardsForPrefabName == null) { GenerateSpawnCards(); } return _SpawnCardsForPrefabName; } } protected InstancedLoot Plugin => Manager.Plugin; public abstract string[] HandledObjectTypes { get; } public abstract ObjectInstanceMode ObjectInstanceMode { get; } public static void GenerateSpawnCards() { InteractableSpawnCard[] array = Resources.FindObjectsOfTypeAll<InteractableSpawnCard>(); if (_SpawnCardsForPrefabName == null) { _SpawnCardsForPrefabName = new Dictionary<string, SpawnCard>(); } InteractableSpawnCard[] array2 = array; foreach (InteractableSpawnCard val in array2) { string name = ((Object)((SpawnCard)val).prefab).name; if (!_SpawnCardsForPrefabName.ContainsKey(name)) { _SpawnCardsForPrefabName.Add(name, (SpawnCard)(object)val); } } } public virtual void Init(ObjectHandlerManager manager) { Manager = manager; } public virtual bool CanObjectBeOwned(string objectType) { return false; } public virtual bool IsValidForObject(string objectType, GameObject gameObject) { return true; } public virtual void InstanceObject(string objectType, GameObject gameObject, PlayerCharacterMasterController[] players) { InstanceHandler.SharedInstanceInfo sharedInstanceInfo = new InstanceHandler.SharedInstanceInfo(); sharedInstanceInfo.SourceObject = gameObject; sharedInstanceInfo.ObjectInstanceMode = ObjectInstanceMode; InstanceHandler[] array; PlayerCharacterMasterController[] players2; switch (ObjectInstanceMode) { case ObjectInstanceMode.InstancedObject: array = new InstanceHandler[1]; players2 = players; break; case ObjectInstanceMode.CopyObject: array = new InstanceHandler[players.Length]; players2 = (PlayerCharacterMasterController[])(object)new PlayerCharacterMasterController[1] { players[0] }; break; default: throw new InvalidOperationException("Object handler doesn't support instancing objects (?)"); } (array[0] = InstanceSingleObjectFrom(gameObject, gameObject, players2)).SharedInfo = sharedInstanceInfo; if (ObjectInstanceMode == ObjectInstanceMode.CopyObject) { for (int i = 1; i < players.Length; i++) { GameObject val = CloneObject(objectType, gameObject); if ((Object)(object)val != (Object)null) { AwaitObjectFor(val, new AwaitedObjectInfo { SourceObject = gameObject, Players = (PlayerCharacterMasterController[])(object)new PlayerCharacterMasterController[1] { players[i] } }); } } } FinalizeSourceObjectIfNotAwaited(gameObject); } public virtual GameObject CloneObject(string objectType, GameObject gameObject) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; SpawnCard value = null; SpawnCardTracker component = gameObject.GetComponent<SpawnCardTracker>(); if ((Object)(object)component != (Object)null) { value = component.SpawnCard; } if ((Object)(object)value == (Object)null) { string key = ((Object)gameObject).name.Replace("(Cloned)", ""); SpawnCardsForPrefabName.TryGetValue(key, out value); } if ((Object)(object)value != (Object)null) { DirectorSpawnRequest val2 = new DirectorSpawnRequest(value, (DirectorPlacementRule)null, new Xoroshiro128Plus(0uL)); val = value.DoSpawn(gameObject.transform.position, gameObject.transform.rotation, val2).spawnedInstance; if ((Object)(object)val != (Object)null) { val.transform.position = gameObject.transform.position; val.transform.rotation = gameObject.transform.rotation; val.transform.localScale = gameObject.transform.localScale; } } else { Plugin._logger.LogError((object)$"Failed to find spawn card for {gameObject}, objectType {objectType}"); } return val; } public virtual InstanceHandler InstanceSingleObjectFrom(GameObject source, GameObject target, PlayerCharacterMasterController[] players) { InstanceHandler instanceHandler = target.AddComponent<InstanceHandler>(); instanceHandler.SetPlayers(players, sync: false); if (ObjectInstanceMode == ObjectInstanceMode.CopyObject) { instanceHandler.OrigPlayer = players[0]; InstanceInfoTracker component = source.GetComponent<InstanceInfoTracker>(); if ((Object)(object)component != (Object)null) { component.Info.AttachTo(target); } InstanceHandler component2 = source.GetComponent<InstanceHandler>(); instanceHandler.SharedInfo = component2.SharedInfo; } return instanceHandler; } public virtual void FinalizeSourceObjectIfNotAwaited(GameObject sourceObject) { if (InfoForAwaitedObjects.All((KeyValuePair<GameObject, AwaitedObjectInfo> pair) => (Object)(object)pair.Value.SourceObject != (Object)(object)sourceObject)) { FinalizeObject(sourceObject); } } public virtual void FinalizeObject(GameObject sourceObject) { InstanceHandler component = sourceObject.GetComponent<InstanceHandler>(); component.SharedInfo.SyncToAll(); foreach (InstanceHandler linkedHandler in component.SharedInfo.LinkedHandlers) { linkedHandler.UpdateVisuals(); } } public virtual void AwaitObjectFor(GameObject target, AwaitedObjectInfo info) { InfoForAwaitedObjects.Add(target, info); Manager.RegisterAwaitedObject(target, this); } public virtual void HandleAwaitedObject(GameObject target) { AwaitedObjectInfo awaitedObjectInfo = InfoForAwaitedObjects[target]; InfoForAwaitedObjects.Remove(target); InstanceSingleObjectFrom(awaitedObjectInfo.SourceObject, target, awaitedObjectInfo.Players); FinalizeSourceObjectIfNotAwaited(awaitedObjectInfo.SourceObject); } } [BepInPlugin("com.kuberoot.instancedloot", "InstancedLoot", "1.3.0")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class InstancedLoot : BaseUnityPlugin { public HookManager HookManager; public ObjectHandlerManager ObjectHandlerManager; public static List<SyncInstances.InstanceHandlerEntry[]> FailedSyncs = new List<SyncInstances.InstanceHandlerEntry[]>(); internal ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; public static InstancedLoot Instance { get; private set; } public Config ModConfig { get; private set; } public static event Action<InstancedLoot> PreConfigInit; public void Awake() { ModConfig = new Config(this, ((BaseUnityPlugin)this).Logger); HookManager = new HookManager(this); ObjectHandlerManager = new ObjectHandlerManager(this); NetworkingAPI.RegisterMessageType<SyncInstances>(); } public void Start() { InstancedLoot.PreConfigInit?.Invoke(this); ModConfig.Init(); } public void OnEnable() { Instance = this; PlayerCharacterMasterController.onPlayerAdded += OnPlayerAdded; HookManager.RegisterHooks(); } public void OnDisable() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } HookManager.UnregisterHooks(); PlayerCharacterMasterController.onPlayerAdded -= OnPlayerAdded; HookEndpointManager.RemoveAllOwnedBy(HookEndpointManager.GetOwner((Delegate)new Action(OnDisable))); InstancedLootBehaviour[] array = Object.FindObjectsOfType<InstancedLootBehaviour>(); foreach (InstancedLootBehaviour instancedLootBehaviour in array) { if ((Object)(object)instancedLootBehaviour != (Object)null) { Object.Destroy((Object)(object)instancedLootBehaviour); } } } private void OnPlayerAdded(PlayerCharacterMasterController player) { if (!NetworkServer.active || (Object)(object)player == (Object)null || (Object)(object)player.networkUser == (Object)null || ((NetworkBehaviour)player.networkUser).connectionToClient == null) { return; } HashSet<InstanceHandler> hashSet = new HashSet<InstanceHandler>(); foreach (InstanceHandler instance in InstanceHandler.Instances) { InstanceHandler instanceHandler = instance.LinkedHandlers?[0] ?? instance; if (!hashSet.Contains(instanceHandler)) { hashSet.Add(instanceHandler); instanceHandler.SyncToPlayer(player); } } } public void HandleInstancing(GameObject obj, InstanceInfoTracker.InstanceOverrideInfo? overrideInfo = null, bool isObject = true) { //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) InstanceInfoTracker instanceInfoTracker = obj.GetComponent<InstanceInfoTracker>(); InstanceInfoTracker.InstanceOverrideInfo? instanceOverrideInfo = (((Object)(object)instanceInfoTracker == (Object)null) ? null : new InstanceInfoTracker.InstanceOverrideInfo?(instanceInfoTracker.Info)); if ((Object)(object)instanceInfoTracker == (Object)null) { instanceInfoTracker = null; } string text = overrideInfo?.ObjectType ?? instanceOverrideInfo?.ObjectType; PlayerCharacterMasterController val = overrideInfo?.Owner; if ((Object)(object)val == (Object)null) { val = instanceOverrideInfo?.Owner; } if ((Object)(object)instanceInfoTracker == (Object)null && text == null) { return; } InstanceMode instanceMode = ModConfig.GetInstanceMode(text ?? instanceOverrideInfo?.ObjectType); if (instanceMode == InstanceMode.None) { return; } bool flag = false; bool flag2 = false; bool flag3 = false; if (instanceOverrideInfo?.ObjectType == null) { switch (instanceMode) { case InstanceMode.InstanceObject: case InstanceMode.InstanceBoth: flag = true; flag2 = false; break; case InstanceMode.InstanceObjectForOwnerOnly: case InstanceMode.InstanceBothForOwnerOnly: flag = true; flag2 = true; break; } } GenericPickupController component = obj.GetComponent<GenericPickupController>(); if ((Object)(object)component != (Object)null) { PickupDef pickupDef = PickupCatalog.GetPickupDef(component.pickupIndex); if (((pickupDef == null) ? (-1) : ((int)pickupDef.itemIndex)) != -1) { goto IL_016f; } } if ((Object)(object)obj.GetComponent<PickupPickerController>() != (Object)null) { goto IL_016f; } goto IL_01a7; IL_01a7: if (!flag3 && flag) { flag = ObjectHandlerManager.CanInstanceObject(text, obj); } if (overrideInfo.HasValue) { overrideInfo.Value.AttachTo(obj); } if (flag && (!flag2 || !((Object)(object)val == (Object)null) || instanceOverrideInfo?.PlayerOverride != null)) { HashSet<PlayerCharacterMasterController> hashSet = ((instanceOverrideInfo?.PlayerOverride != null) ? new HashSet<PlayerCharacterMasterController>(instanceOverrideInfo?.PlayerOverride) : ((!flag2) ? ModConfig.GetValidPlayersSet() : new HashSet<PlayerCharacterMasterController> { val })); if (flag3) { InstanceHandler instanceHandler = obj.AddComponent<InstanceHandler>(); instanceHandler.SharedInfo = new InstanceHandler.SharedInstanceInfo { ObjectInstanceMode = ObjectInstanceMode.InstancedObject }; instanceHandler.SetPlayers(hashSet); } else { ObjectHandlerManager.InstanceObject(text, obj, hashSet.ToArray()); } } return; IL_016f: if (!isObject) { flag3 = true; switch (instanceMode) { case InstanceMode.InstanceObject: flag = false; break; case InstanceMode.InstanceBoth: case InstanceMode.InstanceItemForOwnerOnly: flag = true; flag2 = true; break; case InstanceMode.InstanceItems: flag = true; flag2 = false; break; } } goto IL_01a7; } public static bool CanUninstance(InstanceHandler instanceHandler, PlayerCharacterMasterController player) { if (!instanceHandler.Players.Contains(player)) { return false; } if (instanceHandler.AllPlayers.Count == 1) { return true; } if (Object.op_Implicit((Object)(object)((Component)instanceHandler).GetComponent<CreatePickupInfoTracker>())) { return true; } return false; } public void HandleUninstancing(InstanceHandler instanceHandler, PlayerCharacterMasterController player) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_0099: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (!instanceHandler.Players.Contains(player)) { return; } CreatePickupInfoTracker component = ((Component)instanceHandler).GetComponent<CreatePickupInfoTracker>(); if (Object.op_Implicit((Object)(object)component)) { Vector3 val = ((Component)instanceHandler).transform.position - (((Object)(object)player.body != (Object)null) ? player.body.transform.position : Vector3.zero); val.y = 0.01f; ((Vector3)(ref val)).Normalize(); CreatePickupInfo createPickupInfo = component.CreatePickupInfo; createPickupInfo.position = ((Component)instanceHandler).transform.position + Vector3.up * 3f; PickupDropletController.CreatePickupDroplet(createPickupInfo, createPickupInfo.position, Vector3.up * 10f + val * 5f); instanceHandler.RemovePlayer(player); if (instanceHandler.Players.Count == 0) { Object.Destroy((Object)(object)((Component)instanceHandler).gameObject); } } } } public class ObjectHandlerManager { public readonly Dictionary<Type, AbstractObjectHandler> ObjectHandlers = new Dictionary<Type, AbstractObjectHandler>(); public readonly Dictionary<string, AbstractObjectHandler> HandlersForObjectType = new Dictionary<string, AbstractObjectHandler>(); public readonly Dictionary<GameObject, AbstractObjectHandler> AwaitedObjects = new Dictionary<GameObject, AbstractObjectHandler>(); public readonly InstancedLoot Plugin; public ObjectHandlerManager(InstancedLoot pluginInstance) { Plugin = pluginInstance; RegisterHandler<ChestHandler>(); RegisterHandler<ShrineChanceHandler>(); RegisterHandler<RouletteChestHandler>(); RegisterHandler<MultiShopHandler>(); RegisterHandler<OptionChestHandler>(); RegisterHandler<PrinterHandler>(); RegisterHandler<ScrapperHandler>(); RegisterHandler<SpecialItemHandler>(); RegisterHandler<SpecialObjectHandler>(); } public void RegisterHandler<T>() where T : AbstractObjectHandler, new() { T val = new T(); val.Init(this); ObjectHandlers[typeof(T)] = val; string[] handledObjectTypes = val.HandledObjectTypes; foreach (string key in handledObjectTypes) { HandlersForObjectType[key] = val; } } public T GetHandler<T>() where T : AbstractObjectHandler { return (T)ObjectHandlers[typeof(T)]; } public void InstanceObject(string objectType, GameObject gameObject, PlayerCharacterMasterController[] players) { HandlersForObjectType[objectType].InstanceObject(objectType, gameObject, players); } public InstanceHandler InstanceSingleObject(string objectType, GameObject sourceGameObject, GameObject targetGameObject, PlayerCharacterMasterController[] players) { return HandlersForObjectType[objectType].InstanceSingleObjectFrom(sourceGameObject, targetGameObject, players); } public bool CanInstanceObject(string objectType, GameObject gameObject) { if (HandlersForObjectType.TryGetValue(objectType, out var value)) { return value.IsValidForObject(objectType, gameObject); } return false; } public void RegisterAwaitedObject(GameObject gameObject, AbstractObjectHandler owningHandler) { AwaitedObjects.Add(gameObject, owningHandler); } public bool HandleAwaitedObject(GameObject gameObject) { if (AwaitedObjects.TryGetValue(gameObject, out var value)) { AwaitedObjects.Remove(gameObject); value.HandleAwaitedObject(gameObject); return true; } return false; } } public class Utils { public static bool IsObjectInteractibleForPlayer(GameObject gameObject, PlayerCharacterMasterController player) { if ((Object)(object)gameObject == (Object)null) { return true; } InstanceHandler component = gameObject.GetComponent<InstanceHandler>(); if ((Object)(object)component != (Object)null) { if (component.AllPlayers.Contains(player)) { return component.LinkedHandlers.Where((InstanceHandler handler) => handler.Players.Contains(player)).Any(delegate(InstanceHandler handler) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) IInteractable component2 = ((Component)handler).GetComponent<IInteractable>(); if (component2 != null) { CharacterBody body = player.body; if (Object.op_Implicit((Object)(object)body)) { Interactor component3 = ((Component)body).GetComponent<Interactor>(); if (Object.op_Implicit((Object)(object)component3) && (int)component2.GetInteractability(component3) == 0) { return false; } } } return true; }); } return component.AllPlayers.Contains(player); } return true; } public static bool IsObjectInstanceInteractibleForPlayer(GameObject gameObject, PlayerCharacterMasterController player) { if ((Object)(object)gameObject == (Object)null) { return true; } InstanceHandler component = gameObject.GetComponent<InstanceHandler>(); if ((Object)(object)component != (Object)null) { return component.Players.Contains(player); } return true; } public static bool IsObjectInteractibleForCameraRigController(GameObject gameObject, CameraRigController cameraRigController) { if ((Object)(object)cameraRigController == (Object)null) { return true; } CharacterBody targetBody = cameraRigController.targetBody; if ((Object)(object)targetBody == (Object)null) { return true; } CharacterMaster master = targetBody.master; if ((Object)(object)master == (Object)null) { return true; } PlayerCharacterMasterController playerCharacterMasterController = master.playerCharacterMasterController; if ((Object)(object)playerCharacterMasterController == (Object)null) { return true; } return IsObjectInteractibleForPlayer(gameObject, playerCharacterMasterController); } public static bool IsObjectInstanceInteractibleForCameraRigController(GameObject gameObject, CameraRigController cameraRigController) { if ((Object)(object)cameraRigController == (Object)null) { return true; } CharacterBody targetBody = cameraRigController.targetBody; if ((Object)(object)targetBody == (Object)null) { return true; } CharacterMaster master = targetBody.master; if ((Object)(object)master == (Object)null) { return true; } PlayerCharacterMasterController playerCharacterMasterController = master.playerCharacterMasterController; if ((Object)(object)playerCharacterMasterController == (Object)null) { return true; } return IsObjectInstanceInteractibleForPlayer(gameObject, playerCharacterMasterController); } public static bool IncreasesItemCount(InstanceMode instanceMode) { if ((uint)(instanceMode - 2) <= 2u) { return true; } return false; } } } namespace InstancedLoot.ObjectHandlers { public class ChestHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[15] { "Chest1", "Chest2", "GoldChest", "Chest1StealthedVariant", "CategoryChestDamage", "CategoryChestHealing", "CategoryChestUtility", "CategoryChest2Damage", "CategoryChest2Healing", "CategoryChest2Utility", "EquipmentBarrel", "LunarChest", "VoidChest", "Lockbox", "ScavBackpack" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.CopyObject; public override bool CanObjectBeOwned(string objectType) { if (objectType == "Lockbox") { return true; } return base.CanObjectBeOwned(objectType); } public override bool IsValidForObject(string objectType, GameObject gameObject) { return (Object)(object)gameObject.GetComponent<ChestBehavior>() != (Object)null; } public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<ChestBehaviorHandler>(); base.Plugin.HookManager.RegisterHandler<PurchaseInteractionHandler>(); base.Plugin.HookManager.RegisterHandler<ScavBackpackOpeningHandler>(); } public override InstanceHandler InstanceSingleObjectFrom(GameObject source, GameObject target, PlayerCharacterMasterController[] players) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) ChestBehavior component = source.GetComponent<ChestBehavior>(); ChestBehavior component2 = target.GetComponent<ChestBehavior>(); component2.rng = new Xoroshiro128Plus(component.rng); component2.dropCount = component.dropCount; component2.dropPickup = component.dropPickup; return base.InstanceSingleObjectFrom(source, target, players); } } public class LunarShopHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[1] { "LunarShopTerminal" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.InstancedObject; } public class MultiShopHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[3] { "TripleShop", "TripleShopEquipment", "FreeChestMultiShop" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.CopyObject; public override bool CanObjectBeOwned(string objectType) { if (objectType == "FreeChestMultiShop") { return true; } return base.CanObjectBeOwned(objectType); } public override bool IsValidForObject(string objectType, GameObject gameObject) { if (!((Object)(object)gameObject.GetComponent<MultiShopController>() != (Object)null)) { return (Object)(object)gameObject.GetComponent<ShopTerminalBehavior>() != (Object)null; } return true; } public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<MultiShopControllerHandler>(); base.Plugin.HookManager.RegisterHandler<ShopTerminalBehaviorHandler>(); base.Plugin.HookManager.RegisterHandler<PurchaseInteractionHandler>(); } public override InstanceHandler InstanceSingleObjectFrom(GameObject source, GameObject target, PlayerCharacterMasterController[] players) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_003a: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) InstanceHandler instanceHandler = base.InstanceSingleObjectFrom(source, target, players); if ((Object)(object)source == (Object)(object)target) { InstanceInfoTracker component = source.GetComponent<InstanceInfoTracker>(); MultiShopController component2 = source.GetComponent<MultiShopController>(); ShopTerminalBehavior component3 = source.GetComponent<ShopTerminalBehavior>(); if ((Object)(object)component2 != (Object)null) { Enumerator<GameObject> enumerator = component2.terminalGameObjects.GetEnumerator(); try { while (enumerator.MoveNext()) { GameObject current = enumerator.Current; InstanceSingleObjectFrom(current, current, players); if ((Object)(object)component != (Object)null) { component.Info.AttachTo(current); } } } finally { ((IDisposable)enumerator).Dispose(); } } if ((Object)(object)component3 != (Object)null) { instanceHandler.SharedInfo = new InstanceHandler.SharedInstanceInfo { SourceObject = target, ObjectInstanceMode = ObjectInstanceMode }; } } else { MultiShopController component4 = target.GetComponent<MultiShopController>(); if ((Object)(object)component4 != (Object)null) { MultiShopController component5 = source.GetComponent<MultiShopController>(); component4.rng = new Xoroshiro128Plus(0uL); component4.CreateTerminals(); component4.Networkcost = component5.Networkcost; component4.rng = new Xoroshiro128Plus(component5.rng); GameObject[] terminalGameObjects = component5._terminalGameObjects; GameObject[] terminalGameObjects2 = component4._terminalGameObjects; for (int i = 0; i < terminalGameObjects2.Length; i++) { AwaitObjectFor(terminalGameObjects2[i], new AwaitedObjectInfo { SourceObject = terminalGameObjects[i], Players = players }); } } ShopTerminalBehavior component6 = target.GetComponent<ShopTerminalBehavior>(); if ((Object)(object)component6 != (Object)null) { ShopTerminalBehavior component7 = source.GetComponent<ShopTerminalBehavior>(); component6.hasStarted = true; component6.rng = new Xoroshiro128Plus(component7.rng); component6.NetworkpickupIndex = component7.NetworkpickupIndex; component6.Networkhidden = component7.Networkhidden; component6.UpdatePickupDisplayAndAnimations(); } PurchaseInteraction component8 = target.GetComponent<PurchaseInteraction>(); if ((Object)(object)component8 != (Object)null) { PurchaseInteraction component9 = source.GetComponent<PurchaseInteraction>(); component8.rng = component9.rng; component8.Networkcost = component9.Networkcost; } } return instanceHandler; } } public class OptionChestHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[2] { "VoidTriple", "LockboxVoid" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.CopyObject; public override bool CanObjectBeOwned(string objectType) { if (objectType == "LockboxVoid") { return true; } return base.CanObjectBeOwned(objectType); } public override bool IsValidForObject(string objectType, GameObject gameObject) { return (Object)(object)gameObject.GetComponent<OptionChestBehavior>() != (Object)null; } public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<OptionChestBehaviorHandler>(); base.Plugin.HookManager.RegisterHandler<PurchaseInteractionHandler>(); } public override InstanceHandler InstanceSingleObjectFrom(GameObject source, GameObject target, PlayerCharacterMasterController[] players) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown OptionChestBehavior component = source.GetComponent<OptionChestBehavior>(); OptionChestBehavior component2 = target.GetComponent<OptionChestBehavior>(); component2.rng = new Xoroshiro128Plus(component.rng); component2.generatedDrops = component.generatedDrops.ToArray(); return base.InstanceSingleObjectFrom(source, target, players); } } public class PrinterHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[8] { "Duplicator", "DuplicatorLarge", "DuplicatorWild", "DuplicatorMilitary", "LunarCauldron_WhiteToGreen", "LunarCauldron_GreenToRed", "LunarCauldron_RedToWhite", "ShrineCleanse" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.None; public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<ShopTerminalBehaviorHandler>(); base.Plugin.HookManager.RegisterHandler<PurchaseInteractionHandler>(); } } public class RouletteChestHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[1] { "CasinoChest" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.CopyObject; public override bool IsValidForObject(string objectType, GameObject gameObject) { return (Object)(object)gameObject.GetComponent<RouletteChestController>() != (Object)null; } public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<RouletteChestControllerHandler>(); base.Plugin.HookManager.RegisterHandler<PurchaseInteractionHandler>(); } public override InstanceHandler InstanceSingleObjectFrom(GameObject source, GameObject target, PlayerCharacterMasterController[] players) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown RouletteChestController component = source.GetComponent<RouletteChestController>(); target.GetComponent<RouletteChestController>().rng = new Xoroshiro128Plus(component.rng); return base.InstanceSingleObjectFrom(source, target, players); } } public class ScrapperHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[1] { "Scrapper" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.None; public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<ScrapperControllerHandler>(); } } public class ShrineChanceHandler : AbstractObjectHandler { public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.CopyObject; public override string[] HandledObjectTypes { get; } = new string[1] { "ShrineChance" }; public override bool IsValidForObject(string objectType, GameObject gameObject) { return (Object)(object)gameObject.GetComponent<ShrineChanceBehavior>() != (Object)null; } public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<ShrineChanceBehaviorHandler>(); base.Plugin.HookManager.RegisterHandler<PurchaseInteractionHandler>(); } public override InstanceHandler InstanceSingleObjectFrom(GameObject source, GameObject target, PlayerCharacterMasterController[] players) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown ShrineChanceBehavior component = source.GetComponent<ShrineChanceBehavior>(); ShrineChanceBehavior component2 = target.GetComponent<ShrineChanceBehavior>(); component2.rng = new Xoroshiro128Plus(component.rng); component2.purchaseInteraction.Networkcost = component.purchaseInteraction.Networkcost; return base.InstanceSingleObjectFrom(source, target, players); } } public class SpecialItemHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[5] { "Sacrifice", "TrophyHuntersTricorn", "BossGroup", "TeleporterBoss", "SuperRoboBallEncounter" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.None; public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<SacrificeArtifactManagerHandler>(); base.Plugin.HookManager.RegisterHandler<BossHunterHandler>(); base.Plugin.HookManager.RegisterHandler<BossGroupHandler>(); } } public class SpecialObjectHandler : AbstractObjectHandler { public override string[] HandledObjectTypes { get; } = new string[2] { "ShrineBlood", "ShrineRestack" }; public override ObjectInstanceMode ObjectInstanceMode => ObjectInstanceMode.CopyObject; public override void Init(ObjectHandlerManager manager) { base.Init(manager); base.Plugin.HookManager.RegisterHandler<ShrineBloodBehaviorHandler>(); base.Plugin.HookManager.RegisterHandler<ShrineRestackBehaviorHandler>(); } public override InstanceHandler InstanceSingleObjectFrom(GameObject source, GameObject target, PlayerCharacterMasterController[] players) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown ShrineRestackBehavior component = target.GetComponent<ShrineRestackBehavior>(); if ((Object)(object)component != (Object)null) { ShrineRestackBehavior component2 = source.GetComponent<ShrineRestackBehavior>(); component.purchaseInteraction = ((Component)component).GetComponent<PurchaseInteraction>(); component.rng = new Xoroshiro128Plus(component2.rng); } ShrineBloodBehavior component3 = target.GetComponent<ShrineBloodBehavior>(); if ((Object)(object)component3 != (Object)null) { component3.purchaseInteraction = ((Component)component3).GetComponent<PurchaseInteraction>(); } return base.InstanceSingleObjectFrom(source, target, players); } } } namespace InstancedLoot.Networking { public class SyncInstances : INetMessage, ISerializableObject { public struct InstanceHandlerEntry { public GameObject target; public GameObject[] players; public GameObject origPlayer; private NetworkInstanceId _target; private NetworkInstanceId[] _players; private NetworkInstanceId _origPlayer; private bool validated; public InstanceHandlerEntry(InstanceHandler instanceHandler) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) _target = default(NetworkInstanceId); _players = null; _origPlayer = default(NetworkInstanceId); validated = false; target = ((Component)instanceHandler).gameObject; players = instanceHandler.Players.Select((PlayerCharacterMasterController player) => ((Component)player).gameObject).ToArray(); origPlayer = (((Object)(object)instanceHandler.OrigPlayer != (Object)null) ? ((Component)instanceHandler.OrigPlayer).gameObject : null); } public bool TryProcess() { //IL_000c: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (validated) { return true; } target = Util.FindNetworkObject(_target); if ((Object)(object)target == (Object)null) { return false; } if (_origPlayer != NetworkInstanceId.Invalid) { origPlayer = Util.FindNetworkObject(_origPlayer); if ((Object)(object)origPlayer == (Object)null) { return false; } } players = (GameObject[])(object)new GameObject[_players.Length]; for (int i = 0; i < _players.Length; i++) { GameObject val = Util.FindNetworkObject(_players[i]); if ((Object)(object)val == (Object)null) { return false; } players[i] = val; } validated = true; return true; } public void Serialize(NetworkWriter writer) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) writer.Write(target.GetComponent<NetworkIdentity>().netId); writer.Write(((Object)(object)origPlayer == (Object)null) ? NetworkInstanceId.Invalid : origPlayer.GetComponent<NetworkIdentity>().netId); writer.Write(players.Count()); GameObject[] array = players; foreach (GameObject val in array) { writer.Write(val.GetComponent<NetworkIdentity>().netId); } } public static InstanceHandlerEntry Deserialize(NetworkReader reader) { //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_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) //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) InstanceHandlerEntry result = default(InstanceHandlerEntry); result.validated = false; result._target = reader.ReadNetworkId(); result._origPlayer = reader.ReadNetworkId(); int num = reader.ReadInt32(); NetworkInstanceId[] array = (NetworkInstanceId[])(object)new NetworkInstanceId[num]; for (int i = 0; i < num; i++) { array[i] = reader.ReadNetworkId(); } result._players = array; return result; } } private NetworkInstanceId _sourceObject; private ObjectInstanceMode objectInstanceMode; private InstanceHandlerEntry[] instanceHandlerEntries; public SyncInstances() { instanceHandlerEntries = Array.Empty<InstanceHandlerEntry>(); } public SyncInstances(InstanceHandler.SharedInstanceInfo instanceInfo) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) instanceHandlerEntries = instanceInfo.LinkedHandlers.Select((InstanceHandler instanceHandler) => new InstanceHandlerEntry(instanceHandler)).ToArray(); objectInstanceMode = instanceInfo.ObjectInstanceMode; _sourceObject = (((Object)(object)instanceInfo.SourceObject == (Object)null) ? NetworkInstanceId.Invalid : instanceInfo.SourceObject.GetComponent<NetworkIdentity>().netId); } public SyncInstances(IEnumerable<InstanceHandler> instanceHandlers) { instanceHandlerEntries = instanceHandlers.Select((InstanceHandler instanceHandler) => new InstanceHandlerEntry(instanceHandler)).ToArray(); } public void Serialize(NetworkWriter writer) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) writer.Write((int)objectInstanceMode); writer.Write(_sourceObject); writer.Write(instanceHandlerEntries.Length); InstanceHandlerEntry[] array = instanceHandlerEntries; foreach (InstanceHandlerEntry instanceHandlerEntry in array) { instanceHandlerEntry.Serialize(writer); } } public void Deserialize(NetworkReader reader) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) objectInstanceMode = (ObjectInstanceMode)reader.ReadInt32(); _sourceObject = reader.ReadNetworkId(); int num = reader.ReadInt32(); instanceHandlerEntries = new InstanceHandlerEntry[num]; for (int i = 0; i < num; i++) { instanceHandlerEntries[i] = InstanceHandlerEntry.Deserialize(reader); } } public void OnReceived() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { ((MonoBehaviour)InstancedLoot.Instance).StartCoroutine(HandleMessageInternal(objectInstanceMode, instanceHandlerEntries, _sourceObject)); } } private IEnumerator HandleMessageInternal(ObjectInstanceMode objectInstanceMode, InstanceHandlerEntry[] entries, NetworkInstanceId _sourceObject) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) bool validated = false; int retryCount = 0; GameObject sourceObject = null; while (!validated) { if (retryCount > 40) { InstancedLoot.Instance._logger.LogError((object)"SyncInstances failed to process too many times; aborting."); InstancedLoot.FailedSyncs.Add(entries); yield break; } retryCount++; validated = true; for (int i = 0; i < entries.Length; i++) { validated = validated && entries[i].TryProcess(); } if ((Object)(object)sourceObject == (Object)null && _sourceObject != NetworkInstanceId.Invalid) { sourceObject = Util.FindNetworkObject(_sourceObject); validated = validated && (Object)(object)sourceObject == (Object)null; } if (!validated) { yield return 0; } } InstanceHandler.SharedInstanceInfo sharedInstanceInfo = new InstanceHandler.SharedInstanceInfo(); sharedInstanceInfo.ObjectInstanceMode = objectInstanceMode; sharedInstanceInfo.SourceObject = sourceObject; for (int j = 0; j < entries.Length; j++) { InstanceHandlerEntry instanceHandlerEntry = entries[j]; InstanceHandler instanceHandler = instanceHandlerEntry.target.GetComponent<InstanceHandler>(); if ((Object)(object)instanceHandler == (Object)null) { instanceHandler = instanceHandlerEntry.target.AddComponent<InstanceHandler>(); } instanceHandler.SetPlayers(instanceHandlerEntry.players.Select((GameObject player) => player.GetComponent<PlayerCharacterMasterController>()), sync: false); if (Object.op_Implicit((Object)(object)instanceHandlerEntry.origPlayer)) { instanceHandler.OrigPlayer = instanceHandlerEntry.origPlayer.GetComponent<PlayerCharacterMasterController>(); } if ((Object)(object)sourceObject != (Object)null) { instanceHandlerEntry.target.transform.position = sourceObject.transform.position; instanceHandlerEntry.target.transform.rotation = sourceObject.transform.rotation; instanceHandlerEntry.target.transform.localScale = sourceObject.transform.localScale; } instanceHandler.SharedInfo = sharedInstanceInfo; } sharedInstanceInfo.RecalculateAllPlayers(); InstanceHandler[] array = (from entry in entries select entry.target.GetComponent<InstanceHandler>() into handler where (Object)(object)handler != (Object)null select handler).ToArray(); for (int j = 0; j < array.Length; j++) { array[j].UpdateVisuals(); } } } } namespace InstancedLoot.Enums { public enum InstanceMode { Default, None, InstanceObject, InstanceItems, InstanceBoth, InstanceObjectForOwnerOnly, InstanceItemForOwnerOnly, InstanceBothForOwnerOnly, InstancePreferred } public enum ObjectInstanceMode { None, CopyObject, InstancedObject } public static class ObjectType { [Description("Small chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsSmall" })] public const string Chest1 = "Chest1"; [Description("Big chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsBig" })] public const string Chest2 = "Chest2"; [Description("Legendary/golden chest")] [ObjectTypeAliases(new string[] { "Chests" })] public const string GoldChest = "GoldChest"; [Description("Stealth chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsSmall" })] public const string Chest1StealthedVariant = "Chest1StealthedVariant"; [Description("Adaptive chest")] [ObjectTypeAliases(new string[] { "Chests" })] public const string CasinoChest = "CasinoChest"; [Description("Shrine of chance")] [ObjectTypeAliases(new string[] { "Shrines" })] public const string ShrineChance = "ShrineChance"; [Description("Equipment barrel\nNote: Equipment itself currently cannot be instanced due to swapping behavior")] [ObjectTypeAliases(new string[] { "Equipment" })] public const string EquipmentBarrel = "EquipmentBarrel"; [Description("Multishop/Triple shop")] [ObjectTypeAliases(new string[] { "Shops" })] public const string TripleShop = "TripleShop"; [Description("Large Multishop/Triple shop")] [ObjectTypeAliases(new string[] { "Shops" })] public const string TripleShopLarge = "TripleShopLarge"; [Description("Equipment Multishop/Triple shop\nNote: Equipment itself currently cannot be instanced due to swapping behavior")] [ObjectTypeAliases(new string[] { "Shops", "Equipment" })] [ObjectTypeDisableInstanceModes(new InstanceMode[] { InstanceMode.InstanceItems, InstanceMode.InstanceBoth })] public const string TripleShopEquipment = "TripleShopEquipment"; [Description("Scrapper")] public const string Scrapper = "Scrapper"; [Description("3D Printer (White items)")] [ObjectTypeAliases(new string[] { "Printers" })] public const string Duplicator = "Duplicator"; [Description("3D Printer (Green items)")] [ObjectTypeAliases(new string[] { "Printers" })] public const string DuplicatorLarge = "DuplicatorLarge"; [Description("Mili-tech printer (Red items)")] [ObjectTypeAliases(new string[] { "Printers" })] public const string DuplicatorMilitary = "DuplicatorMilitary"; [Description("Overgrown 3D printer (Yellow items)")] [ObjectTypeAliases(new string[] { "Printers" })] public const string DuplicatorWild = "DuplicatorWild"; [Description("Rusty lockbox")] [ObjectTypeAliases(new string[] { "ItemSpawned", "PaidWithItem" })] public const string Lockbox = "Lockbox"; [Description("Lunar pod")] [ObjectTypeAliases(new string[] { "Lunar" })] public const string LunarChest = "LunarChest"; [Description("Shipping Request Form delivery")] [ObjectTypeAliases(new string[] { "ItemSpawned" })] public const string FreeChestMultiShop = "FreeChestMultiShop"; [Description("Lunar cauldron (3 White -> 1 Green)")] [ObjectTypeAliases(new string[] { "Cauldrons" })] public const string LunarCauldronWhiteToGreen = "LunarCauldron_WhiteToGreen"; [Description("Lunar cauldron (5 Green -> 1 Red)")] [ObjectTypeAliases(new string[] { "Cauldrons" })] public const string LunarCauldronGreenToRed = "LunarCauldron_GreenToRed"; [Description("Lunar cauldron (1 Red -> 3 White)")] [ObjectTypeAliases(new string[] { "Cauldrons" })] public const string LunarCauldronRedToWhite = "LunarCauldron_RedToWhite"; [Description("Cleansing pool")] [ObjectTypeAliases(new string[] { "PaidWithItem" })] public const string ShrineCleanse = "ShrineCleanse"; [Description("Bazaar shop terminal\nNote: when instanced as an object, rerolling the shop rerolls it for all players")] public const string LunarShopTerminal = "LunarShopTerminal"; [Description("Small damage chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsSmall", "ChestsDamage" })] public const string CategoryChestDamage = "CategoryChestDamage"; [Description("Small healing chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsSmall", "ChestsHealing" })] public const string CategoryChestHealing = "CategoryChestHealing"; [Description("Small utility chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsSmall", "ChestsUtility" })] public const string CategoryChestUtility = "CategoryChestUtility"; [Description("Big damage chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsBig", "ChestsDamage" })] public const string CategoryChest2Damage = "CategoryChest2Damage"; [Description("Big healing chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsBig", "ChestsHealing" })] public const string CategoryChest2Healing = "CategoryChest2Healing"; [Description("Big utility chest")] [ObjectTypeAliases(new string[] { "Chests", "ChestsBig", "ChestsUtility" })] public const string CategoryChest2Utility = "CategoryChest2Utility"; [Description("Void cradle")] [ObjectTypeAliases(new string[] { "Void" })] public const string VoidChest = "VoidChest"; [Description("Void potential (The interactible that costs health, not the orb pickup)")] [ObjectTypeAliases(new string[] { "Void" })] public const string VoidTriple = "VoidTriple"; [Description("Encrusted lockbox")] [ObjectTypeAliases(new string[] { "Void", "ItemSpawned", "PaidWithItem" })] public const string LockboxVoid = "LockboxVoid"; [Description("Scavenger's sack")] public const string ScavBackpack = "ScavBackpack"; [Description("Sacrifice item drop\nNote: the owner for sacrifice is the player delivering the final blow, as recorded in the DamageReport")] public const string Sacrifice = "Sacrifice"; [Description("Trophy Hunter's Tricorn")] public const string HuntersTricorn = "TrophyHuntersTricorn"; [Description("Void fields item drop")] public const string VoidFields = "VoidFields"; [Description("Shrine of Blood")] [ObjectTypeAliases(new string[] { "Shrines" })] [ObjectTypeDisableInstanceModes(new InstanceMode[] { InstanceMode.InstanceItems, InstanceMode.InstanceBoth, InstanceMode.InstanceItemForOwnerOnly })] public const string ShrineBlood = "ShrineBlood"; [Description("Shrine of Order")] [ObjectTypeAliases(new string[] { "Shrines" })] [ObjectTypeDisableInstanceModes(new InstanceMode[] { InstanceMode.InstanceItems, InstanceMode.InstanceBoth, InstanceMode.InstanceItemForOwnerOnly })] public const string ShrineRestack = "ShrineRestack"; [Description("Lunar coin")] [ObjectTypeDisableInstanceModes(new InstanceMode[] { InstanceMode.InstanceItems, InstanceMode.InstanceBoth, InstanceMode.InstanceItemForOwnerOnly })] public const string PickupLunarCoin = "PickupLunarCoin"; [Description("Teleporter boss drop")] public const string TeleporterBoss = "TeleporterBoss"; [Description("Siren's call boss drop")] public const string SuperRoboBallEncounter = "SuperRoboBallEncounter"; [Description("Unknown boss drop")] public const string BossGroup = "BossGroup"; } public static class ObjectAlias { [Description("All chests")] public const string Chests = "Chests"; [Description("Small chests (primarily white items)")] public const string ChestsSmall = "ChestsSmall"; [Description("Big chests (primarily green items)")] public const string ChestsBig = "ChestsBig"; [Description("Damage chests (only drop damage items)")] public const string ChestsDamage = "ChestsDamage"; [Description("Healing chests (only drop healing items)")] public const string ChestsHealing = "ChestsHealing"; [Description("Utility chests (only drop utility items)")] public const string ChestsUtility = "ChestsUtility"; [Description("Item shops - does not include equipment shops, due to equipment shops not supporting item instancing")] public const string Shops = "Shops"; [Description("Item printers, does not include cauldrons")] public const string Printers = "Printers"; [Description("Lunar cauldrons, effectively same as printers, but with exchange rates")] public const string Cauldrons = "Cauldrons"; [Description("Sources of lunar items")] public const string Lunar = "Lunar"; [Description("Void-related objects")] public const string Void = "Void"; [Description("Spawned due to a player having an item. Instancing object for everybody not recommended.")] public const string ItemSpawned = "ItemSpawned"; [Description("Objects that require item payment. Does not include printers for convenience. Examples include lockboxes and cleansing pools.")] public const string PaidWithItem = "PaidWithItem"; [Description("All supported shrines (chance, blood)")] public const string Shrines = "Shrines"; [Description("Sources of guaranteed equipment\nNote: Equipment itself currently cannot be instanced due to swapping behavior")] public const string Equipment = "Equipment"; } } namespace InstancedLoot.Configuration { public class AcceptableValuesInstanceMode : AcceptableValueBase { public SortedSet<InstanceMode> AcceptableValues; public AcceptableValuesInstanceMode(ICollection<InstanceMode> acceptedValues) : base(typeof(InstanceMode)) { AcceptableValues = new SortedSet<InstanceMode>(acceptedValues); } public override object Clamp(object value) { if (((AcceptableValueBase)this).IsValid(value)) { return value; } return InstanceMode.Default; } public override bool IsValid(object value) { return AcceptableValues.Contains((InstanceMode)value); } public override string ToDescriptionString() { return "# Acceptable values: " + string.Join(", ", AcceptableValues.Select((InstanceMode x) => x.ToString()).ToArray()); } } public class Config { public delegate void ObjectTypesDelegate(ISet<string> objectTypes); public delegate void DescribeObjectTypeDelegate(string objectType, List<string> descriptions); public delegate void GenerateAliasesDelegate(string objectType, ISet<string> aliases); public delegate void InstanceModesDelegate(string objectType, ISet<InstanceMode> modes); public delegate void ObjectInstanceModesDelegate(string objectType, ISet<ObjectInstanceMode> modes); public delegate void DescribeAliasesDelegate(string alias, List<string> descriptions); public delegate void GenerateConfigPresetsDelegate(Dictionary<string, ConfigPreset> presets); public readonly InstancedLoot Plugin; private readonly ManualLogSource logger; public ConfigEntry<string> SelectedPreset; public ConfigEntry<bool> SharePickupPickers; public ConfigEntry<InstanceMode> PreferredInstanceMode; public ConfigEntry<bool> ReduceInteractibleBudget; public ConfigEntry<bool> ReduceSacrificeSpawnChance; public ConfigEntry<bool> ReduceBossDrops; public ConfigEntry<bool> ReduceScavengerSackDrops; public ConfigEntry<bool> ReduceMoneyDrops; public ConfigMigrator Migrator; public Dictionary<string, string[]> DefaultAliasesForObjectType = new Dictionary<string, string[]>(); public Dictionary<string, string> DefaultDescriptionsForObjectType = new Dictionary<string, string>(); public Dictionary<string, InstanceMode[]> DefaultDisabledInstanceModesForObjectType = new Dictionary<string, InstanceMode[]>(); public Dictionary<string, string> DefaultDescriptionsForAliases = new Dictionary<string, string>(); public Dictionary<string, ConfigEntry<InstanceMode>> ConfigEntriesForNames = new Dictionary<string, ConfigEntry<InstanceMode>>(); public Dictionary<string, SortedSet<string>> AliasesForObjectType = new Dictionary<string, SortedSet<string>>(); public Dictionary<string, ObjectInstanceMode> ObjectInstanceModeForObject = new Dictionary<string, ObjectInstanceMode>(); public Dictionary<string, ConfigPreset> ConfigPresets = new Dictionary<string, ConfigPreset>(); public Dictionary<string, SortedSet<InstanceMode>> AvailableInstanceModesForObjectType = new Dictionary<string, SortedSet<InstanceMode>>(); private readonly Dictionary<string, InstanceMode> CachedInstanceModes = new Dictionary<string, InstanceMode>(); private static readonly Dictionary<InstanceMode, List<InstanceMode>> InstanceModeReduceMatrix; public bool Ready => true; private ConfigFile config => ((BaseUnityPlugin)Plugin).Config; public event Action OnConfigReady; public event ObjectTypesDelegate GenerateObjectTypes; public event DescribeObjectTypeDelegate DescribeObjectTypes; public event GenerateAliasesDelegate GenerateAliases; public event InstanceModesDelegate LimitInstanceModes; public event ObjectInstanceModesDelegate GenerateObjectInstanceModes; public event DescribeAliasesDelegate DescribeAliases; public event GenerateConfigPresetsDelegate GenerateConfigPresets; public Config(InstancedLoot plugin, ManualLogSource _logger) { Plugin = plugin; logger = _logger; Migrator = new ConfigMigrator(config, this); GenerateObjectTypes += DefaultGenerateObjectTypes; DescribeObjectTypes += DefaultDescribeObjectTypes; GenerateAliases += DefaultGenerateAliases; LimitInstanceModes += DefaultLimitInstanceModes; GenerateObjectInstanceModes += DefaultGenerateObjectInstanceModes; DescribeAliases += DefaultDescribeAliases; GenerateConfigPresets += DefaultGenerateConfigPresets; config.SettingChanged += ConfigOnSettingChanged; OnConfigReady += DoMigrationIfReady; DoMigrationIfReady(); } public void Init() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Expected O, but got Unknown //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_0503: Expected O, but got Unknown //IL_05ae: Unknown result type (might be due to invalid IL or missing references) //IL_05b8: Expected O, but got Unknown PreferredInstanceMode = config.Bind<InstanceMode>("General", "PreferredInstanceMode", InstanceMode.InstanceObject, new ConfigDescription("Preferred instance mode used by some presets. When an entry specifies InstancePreferred for something, it is replaced with the value specified in this config.\nNote: In some cases the mode set here is not available for a specific object type or alias. In those cases, the mode is \"reduced\" to the closest option.\nThis config entry also serves as an explanation for the available instance modes:\nNone: Self-explanatory, this object does not get instanced, nor do items spawned from it\nDefault: Do not override the preset/alias. If every value in the chain is Default, defaults to None.\nInstancePreferred: Use the configuration for PreferredInstanceMode for this entry. Provided for convenience and/or experimentation.\nInstanceObject: Spawn multiple copies of the object, one for each player, where each can only be opened by the owning player, and from which items can be picked up by any player\nInstanceItems: Keep one copy of the object that can be opened by anybody, but instance the spawned item, such that each player can pick it up independently\nInstanceBoth: Spawn multiple copies of the object, like InstanceObject, but also limit the resulting item such that it can only be picked up by the player who earned/bought it\nInstanceItemForOwnerOnly: Keep one copy of the object, and limit the resulting item to only be picked up by the player who earned/bought it.\nInstanceObjectForOwnerOnly: Keep one copy of the object, and limit opening it to only the owning player. This is only meaningful for objects that inherently belong to a player, like lockboxes. The resulting items are not instanced and can be picked up by any player.\nInstanceBothForOwnerOnly: Similar to InstanceObjectForOwnerOnly, but the resulting item can only be picked up by the owning player.", (AcceptableValueBase)(object)new AcceptableValuesInstanceMode(new InstanceMode[7] { InstanceMode.None, InstanceMode.InstanceItems, InstanceMode.InstanceBoth, InstanceMode.InstanceObject, InstanceMode.InstanceItemForOwnerOnly, InstanceMode.InstanceBothForOwnerOnly, InstanceMode.InstanceObjectForOwnerOnly }), Array.Empty<object>())); SharePickupPickers = config.Bind<bool>("General", "SharePickupPickers", false, "Should pickup pickers be shared?\nIf true, pickup pickers (such as void orbs and command essences) will be shared among the players they are instanced for.\nA shared pickup picker can only be opened by one player, and will then drop an item that can be picked up separately.\nIf a pickup picker is not shared, then the item can be selected separately by each player."); ReduceInteractibleBudget = config.Bind<bool>("General - Balance", "ReduceInteractibleBudget", true, "[UNTESTED] Should the interactible budget be reduced to singleplayer levels? (NOTE: Does not account for instance modes)\nIf enabled, the budget used to spawn interactibles (chests, shrines, etc.) in SceneDirector is no longer increased based on player count, and is instead overriden to act as though there's one player.\nIf disabled, you might end up having an increased amount of item drops, with each item drop multiplied by the number of players, causing you to become overpowered."); ReduceSacrificeSpawnChance = config.Bind<bool>("General - Balance", "ReduceSacrificeSpawnChance", true, "[UNTESTED] Should the spawn chance be reduced by the amount of players, if sacrifice item instancing will yield extra items?\nIf enabled, the chance that an enemy drops an item is divided by the number of players in the game.\nIf disabled, you might end up having an increased amount of item drops, due to an increased amount of enemies when playing in multiplayer, combined with items being multiplied by the number of players.\nNote: This is not an accurate method of keeping the amount of items and/or the power level the same as without the mod. I have not checked the formulas or tested the results to ensure fairness, use or don't use this at your own risk."); ReduceBossDrops = config.Bind<bool>("General - Balance", "ReduceBossDrops", true, "Should the boss drop count not scale with player count, if the instancing will yield extra items?\nApplies to teleporter boss drops, as well as the extra boss on Siren's Call, and any other boss drops from BossGroup.\nRecommended when instancing teleporter items, otherwise your boss item drop amount might get increased."); ReduceScavengerSackDrops = config.Bind<bool>("General - Balance", "ReduceScavengerSackDrops", false, "Should the amount of items dropped from a Scavenger's Sack be reduced based on the number of players, if the amount of items is increased as an effect of instancing?\nNote: The amount of items might still not be fair - you might get too few or too many items with this option enabled."); ReduceMoneyDrops = config.Bind<bool>("General - Balance", "ReduceMoneyDrops", false, "[UNTESTED] Should the amount of money dropped from enemies be divided by the number of players?\nNote: Money dropped is an integer, this will probably result in slightly less money overall.\nAlso, it might generally not feel good to play with enabled, causing much longer wait between opening chests."); DefaultDescriptionsForObjectType.Clear(); DefaultAliasesForObjectType.Clear(); DefaultDisabledInstanceModesForObjectType.Clear(); FieldInfo[] fields = typeof(ObjectType).GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo obj in fields) { DescriptionAttribute descriptionAttribute = obj.GetCustomAttributes<DescriptionAttribute>().FirstOrDefault(); ObjectTypeAliasesAttribute objectTypeAliasesAttribute = obj.GetCustomAttributes<ObjectTypeAliasesAttribute>().FirstOrDefault(); ObjectTypeDisableInstanceModesAttribute objectTypeDisableInstanceModesAttribute = obj.GetCustomAttributes<ObjectTypeDisableInstanceModesAttribute>().FirstOrDefault(); if (obj.GetValue(null) is string key) { if (descriptionAttribute != null) { DefaultDescriptionsForObjectType.Add(key, descriptionAttribute.Description); } if (objectTypeAliasesAttribute != null) { DefaultAliasesForObjectType.Add(key, objectTypeAliasesAttribute.Aliases); } if (objectTypeDisableInstanceModesAttribute != null) { DefaultDisabledInstanceModesForObjectType.Add(key, objectTypeDisableInstanceModesAttribute.DisabledInstanceModes); } } } DefaultDescriptionsForAliases.Clear(); fields = typeof(ObjectAlias).GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo obj2 in fields) { DescriptionAttribute descriptionAttribute2 = obj2.GetCustomAttributes<DescriptionAttribute>().FirstOrDefault(); if (obj2.GetValue(null) is string key2 && descriptionAttribute2 != null) { DefaultDescriptionsForAliases.Add(key2, descriptionAttribute2.Description); } } SortedSet<InstanceMode> collection = new SortedSet<InstanceMode> { InstanceMode.Default, InstanceMode.None, InstanceMode.InstanceBoth, InstanceMode.InstanceItems, InstanceMode.InstanceObject, InstanceMode.InstanceItemForOwnerOnly, InstanceMode.InstancePreferred }; SortedSet<ObjectInstanceMode> collection2 = new SortedSet<ObjectInstanceMode> { ObjectInstanceMode.None }; SortedSet<string> sortedSet = new SortedSet<string>(); SortedSet<string> sortedSet2 = new SortedSet<string>(); Dictionary<string, SortedSet<InstanceMode>> dictionary = new Dictionary<string, SortedSet<InstanceMode>>(); this.GenerateObjectTypes(sortedSet); foreach (string item in sortedSet) { SortedSet<ObjectInstanceMode> sortedSet3 = new SortedSet<ObjectInstanceMode>(collection2); this.GenerateObjectInstanceModes(item, sortedSet3); ObjectInstanceModeForObject[item] = sortedSet3.Max; SortedSet<InstanceMode> sortedSet5 = (dictionary[item] = new SortedSet<InstanceMode>(collection)); SortedSet<InstanceMode> sortedSet6 = sortedSet5; this.LimitInstanceModes(item, sortedSet6); AvailableInstanceModesForObjectType[item] = sortedSet6; if (sortedSet6.Count == 0) { continue; } SortedSet<string> sortedSet8 = (AliasesForObjectType[item] = new SortedSet<string>()); SortedSet<string> sortedSet9 = sortedSet8; this.GenerateAliases(item, sortedSet9); List<string> list = new List<string>(); this.DescribeObjectTypes(item, list); string text = "Configure instancing for specific raw objectType"; if (list.Count > 0) { text = text + "\n" + string.Join("\n", list); } ConfigEntriesForNames[item] = config.Bind<InstanceMode>("ObjectTypes", item, InstanceMode.Default, new ConfigDescription(text, (AcceptableValueBase)(object)new AcceptableValuesInstanceMode(sortedSet6), Array.Empty<object>())); foreach (string item2 in sortedSet9) { SortedSet<InstanceMode> sortedSet11; if (!dictionary.ContainsKey(item2)) { sortedSet5 = (dictionary[item2] = new SortedSet<InstanceMode>(sortedSet6)); sortedSet11 = sortedSet5; } else { sortedSet11 = dictionary[item2]; sortedSet11.IntersectWith(sortedSet6); } this.LimitInstanceModes(item2, sortedSet11); sortedSet2.Add(item2); } } foreach (string item3 in sortedSet2) { if (dictionary[item3].Count > 0) { string text2 = "Configure instancing for alias/group of sources"; List<string> list2 = new List<string>(); this.DescribeAliases(item3, list2); if (list2.Count > 0) { text2 = text2 + "\n" + string.Join("\n", list2); } ConfigEntriesForNames[item3] = config.Bind<InstanceMode>("ObjectAliases", item3, InstanceMode.Default, new ConfigDescription(text2, (AcceptableValueBase)(object)new AcceptableValuesInstanceMode(dictionary[item3]), Array.Empty<object>())); } } ConfigPresets = new Dictionary<string, ConfigPreset>(); this.GenerateConfigPresets(ConfigPresets); SelectedPreset = config.Bind<string>("General", "Preset", "Default", new ConfigDescription("Ready to use presets, mostly with sensible defaults.\nNote: Presets can change in updates.\nNote: If you don't like something about a preset, you can override the instancing for specific aliases/object types\nAvailable presets:\n" + string.Join("\n", ConfigPresets.Select((KeyValuePair<string, ConfigPreset> pair) => pair.Key + ": " + pair.Value.Description)), (AcceptableValueBase)(object)new AcceptableValueList<string>(ConfigPresets.Keys.ToArray()), Array.Empty<object>())); } public ConfigPreset GetPreset() { string key = SelectedPreset.Value ?? ""; if (!ConfigPresets.TryGetValue(key, out var value)) { return null; } return value; } public SortedSet<string> GetAliases(string objectType) { if (!AliasesForObjectType.TryGetValue(objectType, out var value)) { return null; } return value; } static Config() { Dictionary<InstanceMode, List<InstanceMode>> dictionary = new Dictionary<InstanceMode, List<InstanceMode>> { { InstanceMode.InstanceBothForOwnerOnly, new List<InstanceMode> { InstanceMode.InstanceObjectForOwnerOnly, InstanceMode.InstanceItemForOwnerOnly } }, { InstanceMode.InstanceObjectForOwnerOnly, new List<InstanceMode> { InstanceMode.InstanceObject } }, { InstanceMode.InstanceBoth, new List<InstanceMode> { InstanceMode.InstanceObject, InstanceMode.InstanceItems } }, { InstanceMode.InstanceObject, new List<InstanceMode> { InstanceMode.InstanceItems } }, { InstanceMode.InstanceItems, new List<InstanceMode> { InstanceMode.InstanceObject } } }; InstanceModeReduceMatrix = new Dictionary<InstanceMode, List<InstanceMode>>(); foreach (KeyValuePair<InstanceMode, List<InstanceMode>> item in dictionary) { List<InstanceMode> list = item.Value.ToList(); for (int i = 0; i < list.Count; i++) { InstanceMode key = list[i]; if (!dictionary.TryGetValue(key, out var value)) { continue; } foreach (InstanceMode item2 in value) { if (!list.Contains(item2)) { list.Add(item2); } } } InstanceModeReduceMatrix[item.Key] = list; } } public InstanceMode ReduceInstanceModeForObjectType(string objectType, InstanceMode mode) { if (mode == InstanceMode.InstancePreferred) { mode = PreferredInstanceMode.Value; } if (mode == InstanceMode.Default) { return mode; } if (!AvailableInstanceModesForObjectType.TryGetValue(objectType, out var value)) { return InstanceMode.None; } if (value.Contains(mode)) { return mode; } if (!InstanceModeReduceMatrix.TryGetValue(mode, out var value2)) { return InstanceMode.None; } foreach (InstanceMode item in value2) { if (value.Contains(item)) { return item; } } Debug.Log((object)("Failed to find reduction for " + objectType)); return InstanceMode.None; } public void MergeInstanceModes(ref InstanceMode orig, InstanceMode other) { if (other == InstanceMode.InstancePreferred) { other = PreferredInstanceMode.Value; } if (other != 0) { orig = other; } } public InstanceMode GetInstanceMode(string objectType) { if (objectType == null) { return InstanceMode.None; } if (CachedInstanceModes.TryGetValue(objectType, out var value)) { return value; } if (!ConfigEntriesForNames.ContainsKey(objectType)) { return InstanceMode.None; } ConfigPreset preset = GetPreset(); SortedSet<string> aliases = GetAliases(objectType); InstanceMode orig = InstanceMode.None; if (preset != null) { if (aliases != null) { foreach (string item in aliases) { MergeInstanceModes(ref orig, ReduceInstanceModeForObjectType(objectType, preset.GetConfigForName(item))); } } MergeInstanceModes(ref orig, ReduceInstanceModeForObjectType(objectType, preset.GetConfigForName(objectType))); } if (aliases != null) { foreach (string item2 in aliases) { MergeInstanceModes(ref orig, ReduceInstanceModeForObjectType(objectType, ConfigEntriesForNames[item2].Value)); } } MergeInstanceModes(ref orig, ReduceInstanceModeForObjectType(objectType, ConfigEntriesForNames[objectType].Value)); CachedInstanceModes[objectType] = orig; return orig; } private void DefaultGenerateObjectTypes(ISet<string> objectTypes) { objectTypes.UnionWith(Plugin.ObjectHandlerManager.HandlersForObjectType.Keys); } private void DefaultDescribeObjectTypes(string objectType, List<string> descriptions) { if (DefaultDescriptionsForObjectType.TryGetValue(objectType, out var value)) { descriptions.Add(value); } } private void DefaultGenerateAliases(string objectType, ISet<string> names) { if (DefaultAliasesForObjectType.TryGetValue(objectType, out var value)) { names.UnionWith(value); } } private void DefaultLimitInstanceModes(string objectType, ISet<InstanceMode> modes) { if (ObjectInstanceModeForObject.TryGetValue(objectType, out var value) && value == ObjectInstanceMode.None) { modes.Remove(InstanceMode.InstanceBoth); modes.Remove(InstanceMode.InstanceObject); } if (DefaultDisabledInstanceModesForObjectType.TryGetValue(objectType, out var value2)) { modes.ExceptWith(value2); } if (Plugin.ObjectHandlerManager.HandlersForObjectType.TryGetValue(objectType, out var value3) && value3.CanObjectBeOwned(objectType)) { if (modes.Contains(InstanceMode.InstanceBoth)) { modes.Add(InstanceMode.InstanceBothForOwnerOnly); } if (modes.Contains(InstanceMode.InstanceObject)) { modes.Add(InstanceMode.InstanceObjectForOwnerOnly); } } } private void DefaultGenerateObjectInstanceModes(string objectType, ISet<ObjectInstanceMode> modes) { if (Plugin.ObjectHandlerManager.HandlersForObjectType.TryGetValue(objectType, out var value)) { modes.Add(value.ObjectInstanceMode); } } private void DefaultDescribeAliases(string alias, List<string> descriptions) { if (DefaultDescriptionsForAliases.TryGetValue(alias, out var value)) { descriptions.Add(value); } SortedSet<string> sortedSet = new SortedSet<string>(); foreach (KeyValuePair<string, SortedSet<string>> item in AliasesForObjectType) { if (item.Value.Contains(alias)) { sortedSet.Add(item.Key); } } descriptions.Add("Full list of included object types:\n" + string.Join(", ", sortedSet)); } private void DefaultGenerateConfigPresets(Dictionary<string, ConfigPreset> presets) { foreach (KeyValuePair<string, ConfigPreset> preset in DefaultPresets.Presets) { presets[preset.Key] = preset.Value; } } private void CheckReadyStatus() { if (Ready) { this.OnConfigReady?.Invoke(); } } private void DoMigrationIfReady() { if (Ready && Migrator.NeedsMigration) { Migrator.DoMigration(); } } public HashSet<PlayerCharacterMasterController> GetValidPlayersSet() { return new HashSet<PlayerCharacterMasterController>(PlayerCharacterMasterController.instances); } private void ConfigOnSettingChanged(object sender, SettingChangedEventArgs e) { if (e.ChangedSetting.SettingType == typeof(InstanceMode) || e.ChangedSetting == SelectedPreset) { CachedInstanceModes.Clear(); } } private void DebugLogInstanceModeForAllObjectTypes() { Debug.Log((object)"Logging instance modes for all object types:"); foreach (string key in AvailableInstanceModesForObjectType.Keys) { Debug.Log((object)$"{key}: {GetInstanceMode(key)}"); } } } public class ConfigMigrator { private static readonly PropertyInfo Property_ConfigFiles_OrphanedEntries = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private readonly ConfigFile config; private readonly Dictionary<ConfigDefinition, string> OrphanedEntries; private readonly Config ModConfig; private static readonly Dictionary<ConfigDefinition, Action<Config, string>> migrations = new Dictionary<ConfigDefinition, Action<Config, string>>(); public bool NeedsMigration => migrations.Keys.Any((ConfigDefinition def) => OrphanedEntries.ContainsKey(def)); public ConfigMigrator(ConfigFile config, Config modConfig) { this.config = config; ModConfig = modConfig; OrphanedEntries = (Dictionary<ConfigDefinition, string>)Property_ConfigFiles_OrphanedEntries.GetValue(config); } public void DoMigration() { List<ConfigDefinition> list = new List<ConfigDefinition>(); foreach (KeyValuePair<ConfigDefinition, Action<Config, string>> migration in migrations) { ConfigDefinition key = migration.Key; Action<Config, string> value = migration.Value; if (OrphanedEntries.TryGetValue(key, out var value2)) { value(ModConfig, value2); list.Add(key); } } foreach (ConfigDefinition item in list) { OrphanedEntries.Remove(item); } config.Save(); } } public class ConfigPreset { protected Dictionary<string, InstanceMode> Configuration; public string Description = "Missing short description for preset"; public ConfigPreset() { } public ConfigPreset(string description, Dictionary<string, InstanceMode> configuration) { Description = description; Configuration = configuration; } public virtual InstanceMode GetConfigForName(string name) { if (!Configuration.TryGetValue(name, out var value)) { return InstanceMode.Default; } return value; } } public static class DefaultPresets { public class EverythingConfigPreset : ConfigPreset { public EverythingConfigPreset() { Description = "Instance absolutely everything. Not recommended."; } public override InstanceMode GetConfigForName(string name) { return InstanceMode.InstancePreferred; } } public static Dictionary<string, ConfigPreset> Presets = new Dictionary<string, ConfigPreset> { { "None", new ConfigPreset("Do not instance anything, vanilla behavior", new Dictionary<string, InstanceMode>()) }, { "Default", new ConfigPreset("Instance most things, tries to be a sensible default.", new Dictionary<string, InstanceMode> { { "Chests", InstanceMode.InstancePreferred }, { "Shops", InstanceMode.InstancePreferred }, { "Shrines", InstanceMode.InstancePreferred }, { "Equipment", InstanceMode.InstanceObject }, { "ItemSpawned", InstanceMode.InstanceObjectForOwnerOnly }, { "LunarChest", InstanceMode.InstancePreferred }, { "VoidTriple", InstanceMode.InstancePreferred }, { "Sacrifice", InstanceMode.InstanceItems }, { "TrophyHuntersTricorn", InstanceMode.InstanceItems } }) }, { "Selfish", new ConfigPreset("Instance things for owner where applicable. Avoids increasing total item/interactible count.", new Dictionary<string, InstanceMode> { { "Chests", InstanceMode.InstanceItemForOwnerOnly }, { "Shops", InstanceMode.InstanceItemForOwnerOnly }, { "Shrines", InstanceMode.InstanceItemForOwnerOnly }, { "Equipment", InstanceMode.InstanceObject }, { "Void", InstanceMode.InstanceItemForOwnerOnly }, { "ItemSpawned", InstanceMode.InstanceBothForOwnerOnly }, { "PaidWithItem", InstanceMode.InstanceItemForOwnerOnly }, { "Printers", InstanceMode.InstanceItemForOwnerOnly }, { "Cauldrons", InstanceMode.InstanceItemForOwnerOnly }, { "Scrapper", InstanceMode.InstanceItemForOwnerOnly }, { "LunarChest", InstanceMode.InstanceItemForOwnerOnly }, { "TeleporterBoss", InstanceMode.InstanceItemForOwnerOnly }, { "BossGroup", InstanceMode.InstanceItemForOwnerOnly }, { "SuperRoboBallEncounter", InstanceMode.InstanceItemForOwnerOnly } }) }, { "EVERYTHING", new EverythingConfigPreset() } }; } public class ItemTierSet : SortedSet<ItemTier> { public static string Serialize(ItemTierSet self) { return string.Join(", ", self.Select((ItemTier x) => ((Object)ItemTierCatalog.GetItemTierDef(x)).name)); } public static ItemTierSet Deserialize(string src) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) ItemTierSet itemTierSet = new ItemTierSet(); foreach (string item in from s in src.Split(',') select s.Trim()) { if (Enum.TryParse<ItemTier>(item, out ItemTier result)) { itemTierSet.Add(result); continue; } ItemTierDef val = ItemTierCatalog.FindTierDef(item); int result2; if ((Object)(object)val != (Object)null) { itemTierSet.Add(val.tier); } else if (int.TryParse(item, out result2)) { itemTierSet.Add((ItemTier)result2); } } return itemTierSet; } public override string ToString() { return Serialize(this); } } } namespace InstancedLoot.Configuration.Attributes { [AttributeUsage(AttributeTargets.Field)] public class DescriptionAttribute : Attribute { public string Description; public DescriptionAttribute(string description) { Description = description; } } [AttributeUsage(AttributeTargets.Field)] public class ObjectTypeAliasesAttribute : Attribute { public string[] Aliases; public ObjectTypeAliasesAttribute(string[] aliases) { Aliases = aliases; } } [AttributeUsage(AttributeTargets.Field)] public class ObjectTypeDisableInstanceModesAttribute : Attribute { public InstanceMode[] DisabledInstanceModes; public ObjectTypeDisableInstanceModesAttribute(InstanceMode[] disabledInstanceModes) { DisabledInstanceModes = disabledInstanceModes; } } } namespace InstancedLoot.Components { public class CreatePickupInfoTracker : InstancedLootBehaviour { public CreatePickupInfo CreatePickupInfo; } public class FadeBehavior : InstancedLootBehaviour { private static readonly int Fade; public float FadeLevel = 0.3f; private bool needsRefresh = true; public HashSet<GameObject> ExtraGameObjects = new HashSet<GameObject>(); public HashSet<Renderer> Renderers; public HashSet<Renderer> DitherModelRenderers; public DitherModel[] DitherModels; private MaterialPropertyBlock propertyStorage; public Behaviour[] ComponentsForPreCull; public static readonly List<FadeBehavior> InstancesList; private CameraRigController lastCameraRigController; private PlayerCharacterMasterController lastPlayer; private PlayerCharacterMasterController lastDitherModelPlayer; private bool lastVisible; private bool isBeingDestroyed; static FadeBehavior() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown Fade = Shader.PropertyToID("_Fade"); InstancesList = new List<FadeBehavior>(); SceneCamera.onSceneCameraPreCull += new SceneCameraDelegate(RefreshForPreCull); SceneCamera.onSceneCameraPreRender += new SceneCameraDelegate(RefreshForPreRender); } public void OnDestroy() { isBeingDestroyed = true; RefreshForPreCull(lastPlayer); RefreshForPreRender(lastPlayer); } public static void RefreshForPreCull(SceneCamera sceneCamera) { RefreshAllInstances(sceneCamera, isPreCull: true); } public static void RefreshForPreRender(SceneCamera sceneCamera) { RefreshAllInstances(sceneCamera, isPreCull: false); } public static void RefreshAllInstances(SceneCamera sceneCamera, bool isPreCull) { CameraRigController cameraRigController = sceneCamera.cameraRigController; if (!Object.op_Implicit((Object)(object)cameraRigController)) { return; } CharacterBody targetBody = cameraRigController.targetBody; if (!Object.op_Implicit((Object)(object)targetBody)) { return; } PlayerCharacterMasterController val = (((Object)(object)targetBody.master != (Object)null) ? targetBody.master.playerCharacterMasterController : null); if (!Object.op_Implicit((Object)(object)val)) { return; } if (isPreCull) { foreach (FadeBehavior instances in InstancesList) { instances.RefreshForPreCull(val); } return; } foreach (FadeBehavior instances2 in InstancesList) { instances2.RefreshForPreRender(val); } } public void RefreshInstanceForCamera(SceneCamera sceneCamera) { CameraRigController cameraRigController = sceneCamera.cameraRigController; if (!Object.op_Implicit((Object)(object)cameraRigController)) { return; } CharacterBody targetBody = cameraRigController.targetBody; if (Object.op_Implicit((Object)(object)targetBody)) { PlayerCharacterMasterController val = (((Object)(object)targetBody.master != (Object)null) ? targetBody.master.playerCharacterMasterController : null); if (Object.op_Implicit((Object)(object)val)) { RefreshForPreRender(val); RefreshForPreCull(val); } } } private void Awake() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown propertyStorage = new MaterialPropertyBlock(); } private void Start() { Refresh(); } private void OnEnable() { InstancesList.Add(this); } private void OnDisable() { InstancesList.Remove(this); } public float GetFadeLevelForCameraRigController(CameraRigController cameraRigController) { if (needsRefresh) { RefreshComponentLists(); } bool flag = false; CharacterBody targetBody = cameraRigController.targetBody; if (Object.op_Implicit((Object)(object)targetBody)) { CharacterMaster master = targetBody.master; if (Object.op_Implicit((Object)(object)master)) { PlayerCharacterMasterController playerCharacterMasterController = master.playerCharacterMasterController; if (Object.op_Implicit((Object)(object)playerCharacterMasterController)) { if ((Object)(object)playerCharacterMasterController == (Object)(object)lastDitherModelPlayer) { flag = lastVisible; } else { InstanceHandler component = ((Component)this).GetComponent<InstanceHandler>(); flag = !Object.op_Implicit((Object)(object)component) || component.IsInstancedFor(playerCharacterMasterController); } lastDitherModelPlayer = playerCharacterMasterController; goto IL_0082; } } } lastDitherModelPlayer = null; goto IL_0082; IL_0082: lastVisible = flag; if (!flag) { return FadeLevel; } return 1f; } private static IEnumerable<T> CustomGetComponents<T>(IEnumerable<GameObject> gameObjects) { return gameObjects.SelectMany((GameObject obj) => obj.GetComponentsInChildren<T>()); } public void RefreshNextFrame() { ((MonoBehaviour)this).StartCoroutine(RefreshNextFrameCoroutine()); IEnumerator RefreshNextFrameCoroutine() { yield return 0; Refresh(); } } public void Refresh() { needsRefresh = true; } public void RefreshComponentLists() { needsRefresh = false; lastPlayer = null; lastCameraRigController = null; ExtraGameObjects.RemoveWhere((GameObject obj) => (Object)(object)obj == (Object)null); HashSet<GameObject> hashSet = new HashSet<GameObject> { ((Component)this).gameObject }; hashSet.UnionWith(ExtraGameObjects); ModelLocator[] componentsInChildren = ((Component)this).GetComponentsInChildren<ModelLocator>(); hashSet.UnionWith(componentsInChildren.Select((ModelLocator modelLocator) => ((Component)modelLocator.modelTransform).gameObject)); hashSet.UnionWith(from hologram in CustomGetComponents<CostHologramContent>(hashSet).ToArray() select ((Component)hologram.targetTextMesh).gameObject); DitherModels = CustomGetComponents<DitherModel>(hashSet).ToArray(); HashSet<Renderer> hashSet2 = new HashSet<Renderer>(); foreach (Renderer item in DitherModels.SelectMany((DitherModel ditherModel) => ditherModel.renderers)) { hashSet2.Add(item); } DitherModelRenderers = hashSet2; hashSet2 = new HashSet<Renderer>(); foreach (Renderer item2 in from renderer in CustomGetComponents<Renderer>(hashSet) where !DitherModelRenderers.Contains(renderer) select renderer) { hashSet2.Add(item2); } Renderers = hashSet2; HashSet<Behaviour> hashSet3 = new HashSet<Behaviour>((IEnumerable<Behaviour>)CustomGetComponents<Highlight>(hashSet)); hashSet3.UnionWith((IEnumerable<Behaviour>)CustomGetComponents<Light>(hashSet)); ComponentsForPreCull = hashSet3.ToArray(); foreach (Renderer renderer in Renderers) { Material[] materials = renderer.materials; for (int i = 0; i < materials.Length; i++) { materials[i].EnableKeyword("DITHER"); } } } public void RefreshForPreCull(PlayerCharacterMasterController player) { if (needsRefresh) { RefreshComponentLists(); } if ((Object)(object)player == (Object)(object)lastPlayer && !isBeingDestroyed) { return; } InstanceHandler component = ((Component)this).GetComponent<InstanceHandler>(); if (((Object)(object)component != (Object)null && component.ObjectInstanceMode != ObjectInstanceMode.CopyObject) || (!((Object)(object)component == (Object)null) && !component.AllOrigPlayers.Contains(player))) { return; } bool enabled = isBeingDestroyed || (Object)(object)component.OrigPlayer == (Object)(object)player; foreach (Renderer renderer in Renderers) { if ((Object)(object)renderer == (Object)null) { if (!isBeingDestroyed) { RefreshComponentLists(); return; } } else { renderer.enabled = enabled; } } foreach (Renderer ditherModelRenderer in DitherModelRenderers) { if ((Object)(object)ditherModelRenderer == (Object)null) { if (!isBeingDestroyed) { RefreshComponentLists(); return; } } else { ditherModelRenderer.enabled = enabled; } } Behaviour[] componentsForPreCull = ComponentsForPreCull; foreach (Behaviour val in componentsForPreCull) { if ((Object)(object)val == (Object)null) { if (!isBeingDestroyed) { RefreshComponentLists(); break; } } else { val.enabled = enabled; } } } public void RefreshForPreRender(PlayerCharacterMasterController player) { if (needsRefresh) { RefreshComponentLists(); } if ((Object)(object)player == (Object)(object)lastPlayer && !isBeingDestroyed) { return; } InstanceHandler component = ((Component)this).GetComponent<InstanceHandler>(); float num = ((isBeingDestroyed || component.IsInstancedFor(player)) ? 1f : FadeLevel); foreach (Renderer renderer in Renderers) { if ((Object)(object)renderer == (Object)null) { if (!isBeingDestroyed) { RefreshComponentLists(); return; } } else { renderer.GetPropertyBlock(propertyStorage); propertyStorage.SetFloat(Fade, num); renderer.SetPropertyBlock(propertyStorage); } } lastPlayer = player; } public static FadeBehavior Attach(GameObject obj) { FadeBehavior component = obj.GetComponent<FadeBehavior>(); if ((Object)(object)component != (Object)null) { component.Refresh(); return component; } return obj.AddComponent<FadeBehavior>(); } } public class InstancedLootBehaviour : MonoBehaviour { } public class InstanceHandler : InstancedLootBehaviour { public class SharedInstanceInfo { public List<InstanceHandler> LinkedHandlers = new List<InstanceHandler>(); public GameObject SourceObject; public readonly HashSet<PlayerCharacterMasterController> AllPlayers = new HashSet<PlayerCharacterMasterController>(); public readonly HashSet<PlayerCharacterMasterController> AllOrigPlayers = new HashSet<PlayerCharacterMasterController>(); public ObjectInstanceMode ObjectInstanceMode; public void RecalculateAllPlayers() { AllPlayers.Clear(); AllOrigPlayers.Clear(); foreach (InstanceHandler linkedHandler in LinkedHandlers) { AllPlayers.UnionWith(linkedHandler.Players); if (Object.op_Implicit((Object)(object)linkedHandler.OrigPlayer)) { AllOrigPlayers.Add(linkedHandler.OrigPlayer); } } UpdateVisuals(); } public void UpdateVisuals() { foreach (InstanceHandler linkedHandler in LinkedHandlers) { linkedHandler.UpdateVisuals(); } } public void SyncTo(NetworkConnection connection) { if (NetworkServer.active) { NetMessageExtensions.Send((INetMessage)(object)new SyncInstances(this), connection); } } public void SyncToAll() { if (NetworkServer.active) { NetMessageExtensions.Send((INetMessage)(object)new SyncInstances(this), (NetworkDestination)1); } } } public HashSet<PlayerCharacterMasterController> Players = new HashSet<PlayerCharacterMasterController>(); public PlayerCharacterMasterController OrigPlayer; private SharedInstanceInfo sharedInfo; public static List<InstanceHandler> Instances = new List<InstanceHandler>(); public ObjectInstanceMode ObjectInstanceMode => sharedInfo?.ObjectInstanceMode ?? ObjectInstanceMode.None; public List<InstanceHandler> LinkedHandlers => sharedInfo?.LinkedHandlers; public GameObject SourceObject => sharedInfo?.SourceObject; public HashSet<PlayerCharacterMasterController> AllPlayers => sharedInfo.AllPlayers; public HashSet<PlayerCharacterMasterController> AllOrigPlayers => sharedInfo.AllOrigPlayers; public SharedInstanceInfo SharedInfo { get { return sharedInfo; } set { if (sharedInfo == value) { return; } if (sharedInfo != null) { sharedInfo.LinkedHandlers.Remove(this); sharedInfo.RecalculateAllPlayers(); } sharedInfo = value; if (sharedInfo != null) { sharedInfo.LinkedHandlers.Add(this); sharedInfo.AllPlayers.UnionWith(Players); if (Object.op_Implicit((Object)(object)OrigPlayer)) { sharedInfo.AllOrigPlayers.Add(OrigPlayer); } sharedInfo.UpdateVisuals(); } } } public void Awake() { Instances.Add(this); FadeBehavior.Attach(((Component)this).gameObject); } public void OnDestroy() { FadeBehavior component = ((Component)this).GetComponent<FadeBehavior>(); if (Object.op_Implicit((Object)(object)component)) { Object.Destroy((Object)(object)component); } Instances.Remove(this); } public void SetPlayers(IEnumerable<PlayerCharacterMasterController> players, bool sync = true) { HashSet<PlayerCharacterMasterController> hashSet = new HashSet<PlayerCharacterMasterController>(); foreach (PlayerCharacterMasterController player in players) { hashSet.Add(player); } Players = hashSet; if (sync) { SyncPlayers(); } } public void RemovePlayer(PlayerCharacterMasterController player, bool sync = true) { Players.Remove(player); if (sync) { SyncPlayers(); } } public void AddPlayer(PlayerCharacterMasterController player, bool sync = true) { Players.Add(player); if (sync) { SyncPlayers(); } } public void SyncPlayers() { sharedInfo.RecalculateAllPlayers(); if (NetworkServer.active) { sharedInfo.SyncToAll(); } UpdateVisuals(); } public void SyncToPlayer(PlayerCharacterMasterController player) { if (NetworkServer.active && !((Object)(object)player == (Object)null) && !((Object)(object)player.networkUser == (Object)null) && ((NetworkBehaviour)player.networkUser).connectionToClient != null) { sharedInfo.SyncTo(((NetworkBehaviour)player.networkUser).connectionToClient); } } public void SyncToConnection(NetworkConnection connection) { if (NetworkServer.active) { sharedInfo.SyncTo(connection); } } public void UpdateVisuals() { FadeBehavior.Attach(((Component)this).gameObject); } public bool IsObjectInstancedFor(PlayerCharacterMasterController player) { return ObjectInstanceMode switch { ObjectInstanceMode.CopyObject => (Object)(object)OrigPlayer == (Object)(object)player, ObjectInstanceMode.InstancedObject => Players.Contains(player), _ => true, }; } public bool IsInstancedFor(PlayerCharacterMasterController player) { return Players.Contains(player); } public bool IsInstancedForInteractor(Interactor interactor) { PlayerCharacterMasterController component = ((Component)interactor).GetComponent<PlayerCharacterMasterController>(); if (Object.op_Implicit((Object)(object)component)) { return IsInstancedFor(component); } return false; } } public class InstanceInfoTracker : InstancedLootBehaviour { public struct InstanceOverrideInfo { public string ObjectType; public PlayerCharacterMasterController Owner; public ItemIndex SourceItemIndex; public PlayerCharacterMasterController[] PlayerOverride; public InstanceOverrideInfo(string objectType = null, PlayerCharacterMasterController owner = null, ItemIndex sourceItemIndex = -1, PlayerCharacterMasterController[] playerOverride = null) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown res