Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of InnangardServerLagFix v1.0.7
plugins/InnangardServerLagFix.dll
Decompiled 3 hours 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.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; [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("InnangardServerLagFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("InnangardServerLagFix")] [assembly: AssemblyTitle("InnangardServerLagFix")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace InnangardServerLagFix { internal static class BedStationManagementTuning { private sealed class PendingBedAssignment { internal object Settler; internal ZDOID Bed; internal float Until; } private const string StationIgnoreKey = "inn_lagfix_ignore_station"; private const string StationToggleRpc = "InnLagFix_StationIgnore_104"; private const string BedAssignRpc = "InnLagFix_BedAssign_104"; private const string BedAssignForceRpc = "InnLagFix_BedAssignForce_104"; private const string BedKey = "inn_bed"; private const string BedClaimKey = "inn_claim"; private const string BedClaimIdentityKey = "inn_claim_identity"; private const long BedOwnerMarker = 424242L; private const float BedAssignWaitSeconds = 4f; private static ManualLogSource _log; private static ConfigEntry<KeyCode> _modifier; private static Type _settlerType; private static Type _restType; private static Type _innConfigType; private static Type _caretakerJobType; private static Type _cookJobType; private static Type _frithType; private static Type _networkRequestType; private static Type[] _stationTypes; private static FieldInfo _settlerViewField; private static FieldInfo _settlerInstancesField; private static PropertyInfo _restProperty; private static PropertyInfo _panelNameProperty; private static PropertyInfo _stableIdentityProperty; private static PropertyInfo _myZdoidProperty; private static PropertyInfo _homePositionProperty; private static MethodInfo _canManageMethod; private static MethodInfo _releaseBedMethod; private static MethodInfo _claimBedMethod; private static MethodInfo _stopSleepMethod; private static FieldInfo _bedSearchRadiusField; private static FieldInfo _caretakerTargetField; private static FieldInfo _cookTargetField; private static FieldInfo _frithInstancesField; private static MethodInfo _frithCoversPointMethod; private static MethodInfo _frithCanManageMethod; private static MethodInfo _networkAuthenticateMethod; private static MethodInfo[] _strictLeadershipMethods = Array.Empty<MethodInfo>(); private static MethodInfo[] _staticLeadershipMethods = Array.Empty<MethodInfo>(); private static MemberInfo[] _strictLeadershipMembers = Array.Empty<MemberInfo>(); private static MemberInfo[] _householdMembers = Array.Empty<MemberInfo>(); private static bool _loggedLeadershipFallback; private static object _selectedSettler; private static float _selectedUntil; private static readonly Dictionary<int, PendingBedAssignment> PendingBeds = new Dictionary<int, PendingBedAssignment>(); private static readonly HashSet<int> RegisteredStationViews = new HashSet<int>(); private static bool _loggedBedFailure; private static bool _loggedStationFailure; private static bool Active { get { if (Plugin.Enabled != null) { return Plugin.Enabled.Value; } return false; } } internal static void Initialize(ConfigFile config, ManualLogSource log, Harmony harmony) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 _log = log; _modifier = config.Bind<KeyCode>("UI", "ResidentStationManagementModifierKey", (KeyCode)306, "Modifier held with Valheim's normal Use/Interact key for Innangard management shortcuts: select a resident for bed reassignment, assign/swap a bed, or toggle an Innangard-operated production station ignored. Default LeftControl + Use. Player use of ignored stations is unchanged."); if ((int)_modifier.Value == 308) { _modifier.Value = (KeyCode)306; } _settlerType = AccessTools.TypeByName("Innangard.SettlerController"); _restType = AccessTools.TypeByName("Innangard.SettlerRest"); _innConfigType = AccessTools.TypeByName("Innangard.InnConfig"); _caretakerJobType = AccessTools.TypeByName("Innangard.Jobs.CaretakerJob"); _cookJobType = AccessTools.TypeByName("Innangard.Jobs.CookJob"); _frithType = AccessTools.TypeByName("Innangard.Frithstone"); _networkRequestType = AccessTools.TypeByName("Innangard.NetworkRequest"); if (_settlerType == null || _restType == null) { _log.LogWarning((object)"[MANAGE] Innangard resident/bed internals not found; bed reassignment disabled."); } else { BindBedInternals(); PatchBedManagement(harmony); } BindStationInternals(); PatchStationManagement(harmony); _log.LogInfo((object)"[MANAGE] LeftControl+Use (configurable): select resident -> assign/swap bed; operated production station -> toggle ignored by Innangard."); } internal static void Tick() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return; } if (_selectedSettler != null && Time.unscaledTime >= _selectedUntil) { _selectedSettler = null; } if (PendingBeds.Count == 0) { return; } List<int> list = null; foreach (KeyValuePair<int, PendingBedAssignment> pendingBed in PendingBeds) { PendingBedAssignment value = pendingBed.Value; if (value == null || value.Settler == null || Time.unscaledTime >= value.Until) { if (list == null) { list = new List<int>(); } list.Add(pendingBed.Key); continue; } ZNetView val = SettlerView(value.Settler); if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && TryAssignBedNow(value.Settler, value.Bed, force: false)) { if (list == null) { list = new List<int>(); } list.Add(pendingBed.Key); } } if (list == null) { return; } foreach (int item in list) { PendingBeds.Remove(item); } } internal static bool IsStationIgnored(ZNetView view) { if (!Active || (Object)(object)view == (Object)null || !view.IsValid() || !ViewBelongsToSupportedStation(view)) { return false; } try { int num; if (view.GetZDO() != null) { num = (view.GetZDO().GetBool("inn_lagfix_ignore_station", false) ? 1 : 0); if (num != 0) { Plugin.ForgetStationLease(view); } } else { num = 0; } return (byte)num != 0; } catch { return false; } } private static void BindBedInternals() { _settlerViewField = AccessTools.Field(_settlerType, "_nview"); _settlerInstancesField = AccessTools.Field(_settlerType, "Instances"); _restProperty = AccessTools.Property(_settlerType, "Rest"); _panelNameProperty = AccessTools.Property(_settlerType, "PanelName"); _stableIdentityProperty = AccessTools.Property(_settlerType, "StableIdentity"); _myZdoidProperty = AccessTools.Property(_settlerType, "MyZdoid"); _homePositionProperty = AccessTools.Property(_settlerType, "HomePosition") ?? AccessTools.Property(_settlerType, "Home"); _canManageMethod = AccessTools.Method(_settlerType, "CanManage", new Type[1] { typeof(long) }, (Type[])null); _releaseBedMethod = AccessTools.Method(_restType, "ReleaseBed", Type.EmptyTypes, (Type[])null); _claimBedMethod = AccessTools.Method(_restType, "ClaimBed", new Type[3] { typeof(Bed), typeof(float), typeof(string) }, (Type[])null); _stopSleepMethod = AccessTools.Method(_restType, "StopSleep", Type.EmptyTypes, (Type[])null); _bedSearchRadiusField = ((_innConfigType != null) ? AccessTools.Field(_innConfigType, "BedSearchRadius") : null); } private static bool TryPatch(Harmony harmony, MethodInfo original, string label, string prefixName = null, string postfixName = null) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (original == null) { return false; } try { HarmonyMethod val = (string.IsNullOrEmpty(prefixName) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(BedStationManagementTuning), prefixName, (Type[])null)); HarmonyMethod val2 = (string.IsNullOrEmpty(postfixName) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(BedStationManagementTuning), postfixName, (Type[])null)); harmony.Patch((MethodBase)original, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } catch (Exception ex) { _log.LogWarning((object)("[MANAGE] Could not patch " + label + "; that management hook is disabled. " + ex.GetType().Name + ": " + ex.Message)); return false; } } private static void PatchBedManagement(Harmony harmony) { MethodInfo methodInfo = AccessTools.Method(_settlerType, "Awake", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(_settlerType, "GetHoverText", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(_settlerType, "Interact", new Type[3] { typeof(Humanoid), typeof(bool), typeof(bool) }, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(Bed), "GetHoverText", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo5 = AccessTools.Method(typeof(Bed), "Interact", new Type[3] { typeof(Humanoid), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo != null) { TryPatch(harmony, methodInfo, "SettlerController.Awake", null, "SettlerAwakePostfix"); } if (methodInfo2 != null) { TryPatch(harmony, methodInfo2, "SettlerController.GetHoverText", null, "SettlerHoverPostfix"); } if (methodInfo3 != null) { TryPatch(harmony, methodInfo3, "SettlerController.Interact", "SettlerInteractPrefix"); } if (methodInfo4 != null) { TryPatch(harmony, methodInfo4, "Bed.GetHoverText", null, "BedHoverPostfix"); } if (methodInfo5 != null) { TryPatch(harmony, methodInfo5, "Bed.Interact", "BedInteractPrefix"); } if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo5 == null || _settlerViewField == null || _restProperty == null || _releaseBedMethod == null || _claimBedMethod == null) { _log.LogWarning((object)"[MANAGE] Some bed-management bindings are missing; bed selection/reassignment may be unavailable."); } } private static void BindStationInternals() { _stationTypes = new Type[3] { typeof(CookingStation), typeof(Smelter), typeof(Fireplace) }; _caretakerTargetField = ((_caretakerJobType != null) ? AccessTools.Field(_caretakerJobType, "_target") : null); _cookTargetField = ((_cookJobType != null) ? AccessTools.Field(_cookJobType, "_target") : null); if (_frithType != null) { _frithInstancesField = AccessTools.Field(_frithType, "Instances"); _frithCoversPointMethod = _frithType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "CoversPoint" && m.GetParameters().Length == 2); _frithCanManageMethod = AccessTools.Method(_frithType, "CanManage", new Type[1] { typeof(long) }, (Type[])null); BindStrictLeadershipInternals(); } _networkAuthenticateMethod = ((_networkRequestType != null) ? AccessTools.Method(_networkRequestType, "AuthenticatePlayer", new Type[3] { typeof(long), typeof(long), typeof(string) }, (Type[])null) : null); if (_frithInstancesField == null || _frithCoversPointMethod == null || _frithCanManageMethod == null || _networkAuthenticateMethod == null) { _log.LogWarning((object)"[STATION-IGNORE] Frith permission/auth bindings are incomplete; station toggles will fail closed rather than allow unmanaged edits."); } } private static void PatchStationManagement(Harmony harmony) { HashSet<MethodInfo> hashSet = new HashSet<MethodInfo>(); HashSet<MethodInfo> hashSet2 = new HashSet<MethodInfo>(); if (_stationTypes != null) { Type[] stationTypes = _stationTypes; foreach (Type type in stationTypes) { if (!(type == null)) { MethodInfo methodInfo = AccessTools.Method(type, "Interact", new Type[3] { typeof(Humanoid), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo != null && hashSet.Add(methodInfo)) { TryPatch(harmony, methodInfo, type.FullName + ".Interact", "StationInteractPrefix"); } MethodInfo methodInfo2 = AccessTools.Method(type, "GetHoverText", Type.EmptyTypes, (Type[])null); if (methodInfo2 != null && hashSet2.Add(methodInfo2)) { TryPatch(harmony, methodInfo2, type.FullName + ".GetHoverText", null, "StationHoverPostfix"); } } } } Type type2 = AccessTools.TypeByName("Switch"); if (type2 != null) { MethodInfo methodInfo3 = AccessTools.Method(type2, "Interact", new Type[3] { typeof(Humanoid), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo3 != null && hashSet.Add(methodInfo3)) { TryPatch(harmony, methodInfo3, "Switch.Interact", "StationInteractPrefix"); } MethodInfo methodInfo4 = AccessTools.Method(type2, "GetHoverText", Type.EmptyTypes, (Type[])null); if (methodInfo4 != null && hashSet2.Add(methodInfo4)) { TryPatch(harmony, methodInfo4, "Switch.GetHoverText", null, "StationHoverPostfix"); } } MethodInfo methodInfo5 = ((_caretakerJobType != null) ? AccessTools.Method(_caretakerJobType, "TargetStillValid", (Type[])null, (Type[])null) : null); if (methodInfo5 != null && _caretakerTargetField != null) { TryPatch(harmony, methodInfo5, "CaretakerJob.TargetStillValid", null, "CaretakerTargetStillValidPostfix"); } MethodInfo methodInfo6 = ((_cookJobType != null) ? AccessTools.Method(_cookJobType, "StillWorthDoing", Type.EmptyTypes, (Type[])null) : null); if (methodInfo6 != null && _cookTargetField != null) { TryPatch(harmony, methodInfo6, "CookJob.StillWorthDoing", null, "CookStillWorthDoingPostfix"); } MethodInfo methodInfo7 = AccessTools.Method(typeof(ZNetView), "Awake", Type.EmptyTypes, (Type[])null); if (methodInfo7 != null) { TryPatch(harmony, methodInfo7, "ZNetView.Awake station RPC registration", null, "ZNetViewAwakePostfix"); } } private static bool ModifierHeld() { //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) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (_modifier == null) { return false; } KeyCode value = _modifier.Value; if ((int)value != 0) { return Input.GetKey(value); } return true; } private unsafe static string ModifierLabel() { //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_0019: Unknown result type (might be due to invalid IL or missing references) KeyCode val = (KeyCode)((_modifier == null) ? 306 : ((int)_modifier.Value)); if ((int)val == 0) { return "E"; } string text = ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString(); if (text.StartsWith("Left", StringComparison.Ordinal)) { text = text.Substring(4); } else if (text.StartsWith("Right", StringComparison.Ordinal)) { text = text.Substring(5); } if (string.Equals(text, "Control", StringComparison.Ordinal)) { text = "Ctrl"; } return text + "+E"; } private static void SettlerAwakePostfix(object __instance) { RegisterSettlerRpc(__instance); } private static void RegisterSettlerRpc(object settler) { if (settler == null) { return; } ZNetView val = SettlerView(settler); if ((Object)(object)val == (Object)null) { return; } try { val.Register<ZDOID>("InnLagFix_BedAssign_104", (Action<long, ZDOID>)delegate(long sender, ZDOID bed) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) HandleBedAssignmentRpc(settler, bed, force: false); }); val.Register<ZDOID>("InnLagFix_BedAssignForce_104", (Action<long, ZDOID>)delegate(long sender, ZDOID bed) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) HandleBedAssignmentRpc(settler, bed, force: true); }); } catch (Exception ex) { if (!_loggedBedFailure) { _loggedBedFailure = true; _log.LogWarning((object)("[BED] Could not register bed-assignment RPC: " + ex.Message)); } } } private static void SettlerHoverPostfix(object __instance, ref string __result) { if (Active && __instance != null && CanLocalPlayerManage(__instance)) { __result = __result + "\n[<color=yellow><b>" + ModifierLabel() + "</b></color>] Reassign Bed"; } } private static bool SettlerInteractPrefix(object __instance, Humanoid __0, bool __1, ref bool __result) { if (!Active || __1 || !ModifierHeld() || __instance == null || !IsLocalPlayer(__0)) { return true; } if (!CanLocalPlayerManage(__instance)) { return true; } _selectedSettler = __instance; _selectedUntil = Time.unscaledTime + 60f; Say("Selected " + PanelName(__instance) + " for bed assignment. " + ModifierLabel() + " a bed to assign or swap it."); __result = true; return false; } private static void BedHoverPostfix(Bed __instance, ref string __result) { object obj = ValidSelectedSettler(); if (Active && obj != null && !((Object)(object)__instance == (Object)null)) { ZNetView val = ViewOf((Component)(object)__instance); if (!((Object)(object)val == (Object)null) && val.IsValid() && BedEligibleForInnangard(__instance, val)) { object obj2 = ResidentClaiming(val.GetZDO()); string text = ((obj2 != null && obj2 != obj) ? ("Swap " + PanelName(obj) + " with " + PanelName(obj2)) : ("Assign to " + PanelName(obj))); __result = __result + "\n[<color=yellow><b>" + ModifierLabel() + "</b></color>] " + text; } } } private static bool BedInteractPrefix(Bed __instance, Humanoid __0, bool __1, ref bool __result) { object obj = ValidSelectedSettler(); if (!Active || obj == null || __1 || !ModifierHeld() || !IsLocalPlayer(__0) || (Object)(object)__instance == (Object)null) { return true; } ZNetView val = ViewOf((Component)(object)__instance); if ((Object)(object)val == (Object)null || !val.IsValid() || !BedEligibleForInnangard(__instance, val)) { Say("That bed cannot be assigned to an Innangard resident."); __result = true; return false; } if (!WithinBedRange(obj, __instance)) { Say("That bed is outside " + PanelName(obj) + "'s Innangard bed-search range."); __result = true; return false; } RequestBedAssignment(obj, __instance, val); _selectedSettler = null; __result = true; return false; } private static void RequestBedAssignment(object selected, Bed targetBed, ZNetView targetView) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) ZNetView val = SettlerView(selected); if ((Object)(object)val == (Object)null || !val.IsValid()) { Say("Could not find that resident's network view."); return; } ZDO zDO = val.GetZDO(); ZDO zDO2 = targetView.GetZDO(); if (zDO == null || zDO2 == null) { return; } ZDOID uid = zDO2.m_uid; ZDOID zDOID = zDO.GetZDOID("inn_bed"); if (zDOID == uid) { Say(PanelName(selected) + " already has that bed."); return; } object obj = ResidentClaiming(zDO2); if (obj != null && obj != selected) { if (zDOID == ZDOID.None) { Say("That bed belongs to " + PanelName(obj) + ", and " + PanelName(selected) + " has no bed to swap with."); return; } Bed val2 = ResolveBed(zDOID); if ((Object)(object)val2 == (Object)null || !WithinBedRange(obj, val2)) { Say("Cannot swap those beds because the current bed is unavailable to " + PanelName(obj) + "."); return; } ZNetView val3 = SettlerView(obj); if ((Object)(object)val3 == (Object)null || !val3.IsValid()) { Say("The resident currently assigned to that bed is not available to swap."); return; } val3.InvokeRPC("InnLagFix_BedAssignForce_104", new object[1] { zDOID }); val.InvokeRPC("InnLagFix_BedAssign_104", new object[1] { uid }); Say("Swapping beds: " + PanelName(selected) + " <-> " + PanelName(obj) + "."); } else if (HasForeignBedClaim(zDO2, selected)) { Say("That bed has an Innangard claim whose resident is not currently loaded; it was left unchanged."); } else { val.InvokeRPC("InnLagFix_BedAssign_104", new object[1] { uid }); Say("Reassigning " + PanelName(selected) + " to that bed."); } } private static void HandleBedAssignmentRpc(object settler, ZDOID desiredBed, bool force) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_007f: Unknown result type (might be due to invalid IL or missing references) if (!Active || settler == null || desiredBed == ZDOID.None) { return; } ZNetView val = SettlerView(settler); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner()) { return; } if (force || TryAssignBedNow(settler, desiredBed, force: false)) { if (force) { TryAssignBedNow(settler, desiredBed, force: true); } return; } object obj = ((settler is Object) ? settler : null); int key = ((obj != null) ? ((Object)obj).GetInstanceID() : settler.GetHashCode()); PendingBeds[key] = new PendingBedAssignment { Settler = settler, Bed = desiredBed, Until = Time.unscaledTime + 4f }; } private unsafe static bool TryAssignBedNow(object settler, ZDOID desiredBed, bool force) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) Bed val = ResolveBed(desiredBed); if (settler == null || (Object)(object)val == (Object)null) { return false; } ZNetView val2 = ViewOf((Component)(object)val); if ((Object)(object)val2 == (Object)null || !val2.IsValid() || !BedEligibleForInnangard(val, val2) || !WithinBedRange(settler, val)) { return false; } ZDO zDO = val2.GetZDO(); if (!force && HasForeignBedClaim(zDO, settler)) { return false; } object obj = _restProperty?.GetValue(settler, null); if (obj == null) { return false; } try { _stopSleepMethod?.Invoke(obj, null); _releaseBedMethod.Invoke(obj, null); float num = Distance(HomePosition(settler), ((Component)val).transform.position); _claimBedMethod.Invoke(obj, new object[3] { val, num, "was reassigned to a bed" }); ManualLogSource log = _log; string[] obj2 = new string[6] { "[BED] ", PanelName(settler), " assigned bed ", null, null, null }; ZDOID val3 = desiredBed; obj2[3] = ((object)(*(ZDOID*)(&val3))/*cast due to .constrained prefix*/).ToString(); obj2[4] = (force ? " (swap leg)" : string.Empty); obj2[5] = "."; log.LogInfo((object)string.Concat(obj2)); return true; } catch (Exception ex) { if (!_loggedBedFailure) { _loggedBedFailure = true; _log.LogWarning((object)("[BED] Bed reassignment failed once; stock bed handling continues. " + ex.GetType().Name + ": " + ex.Message)); } return false; } } private static object ValidSelectedSettler() { if (_selectedSettler == null || Time.unscaledTime >= _selectedUntil) { _selectedSettler = null; return null; } object selectedSettler = _selectedSettler; Component val = (Component)((selectedSettler is Component) ? selectedSettler : null); if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null || !val.gameObject.activeInHierarchy) { _selectedSettler = null; return null; } return _selectedSettler; } private static bool CanLocalPlayerManage(object settler) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (settler == null || (Object)(object)localPlayer == (Object)null) { return false; } long playerID = localPlayer.GetPlayerID(); try { if (_canManageMethod != null) { object obj = _canManageMethod.Invoke(settler, new object[1] { playerID }); if (!(obj is bool) || !(bool)obj) { return false; } } } catch { return false; } return CanRequesterLeadFrith(FindManagingFrith(HomePosition(settler)), playerID); } private static bool BedEligibleForInnangard(Bed bed, ZNetView view) { if ((Object)(object)bed == (Object)null || (Object)(object)view == (Object)null || !view.IsValid()) { return false; } Piece val = ((Component)bed).GetComponent<Piece>() ?? ((Component)bed).GetComponentInParent<Piece>(); if ((Object)(object)val != (Object)null && !val.IsPlacedByPlayer()) { return false; } ZDO zDO = view.GetZDO(); if (zDO == null) { return false; } long num = zDO.GetLong(ZDOVars.s_owner, 0L); if (num != 0L) { return num == 424242; } return true; } private static bool WithinBedRange(object settler, Bed bed) { //IL_0046: 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) if (settler == null || (Object)(object)bed == (Object)null) { return false; } float num = 30f; try { if (_bedSearchRadiusField?.GetValue(null) is ConfigEntry<float> val) { num = Mathf.Max(1f, val.Value); } } catch { } return Distance(HomePosition(settler), ((Component)bed).transform.position) <= num; } private static object ResidentClaiming(ZDO bedZdo) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (bedZdo == null || _settlerInstancesField == null) { return null; } string text = bedZdo.GetString("inn_claim_identity", string.Empty); ZDOID zDOID = bedZdo.GetZDOID("inn_claim"); if (string.IsNullOrEmpty(text) && zDOID == ZDOID.None) { return null; } if (!(_settlerInstancesField.GetValue(null) is IEnumerable enumerable)) { return null; } foreach (object item in enumerable) { if (item == null) { continue; } if (!string.IsNullOrEmpty(text)) { if (_stableIdentityProperty?.GetValue(item, null) as string == text) { return item; } } else if (_myZdoidProperty != null) { object value = _myZdoidProperty.GetValue(item, null); if (value is ZDOID && (ZDOID)value == zDOID) { return item; } } } return null; } private static bool HasForeignBedClaim(ZDO bedZdo, object settler) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (bedZdo == null) { return true; } string text = bedZdo.GetString("inn_claim_identity", string.Empty); if (!string.IsNullOrEmpty(text)) { string text2 = _stableIdentityProperty?.GetValue(settler, null) as string; if (!string.IsNullOrEmpty(text2)) { return text != text2; } return true; } ZDOID zDOID = bedZdo.GetZDOID("inn_claim"); if (zDOID == ZDOID.None) { return false; } if (_myZdoidProperty == null) { return true; } object value = _myZdoidProperty.GetValue(settler, null); if (value is ZDOID) { return (ZDOID)value != zDOID; } return true; } private static Bed ResolveBed(ZDOID id) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (id == ZDOID.None || (Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject val = ZNetScene.instance.FindInstance(id); if ((Object)(object)val == (Object)null) { return null; } return val.GetComponent<Bed>() ?? val.GetComponentInChildren<Bed>(true); } private static ZNetView SettlerView(object settler) { if (settler == null) { return null; } try { object? obj = _settlerViewField?.GetValue(settler); ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null); if ((Object)(object)val != (Object)null) { return val; } } catch { } Component val2 = (Component)((settler is Component) ? settler : null); if (!((Object)(object)val2 != (Object)null)) { return null; } return val2.GetComponent<ZNetView>() ?? val2.GetComponentInParent<ZNetView>(); } private static string PanelName(object settler) { try { string text = _panelNameProperty?.GetValue(settler, null) as string; if (!string.IsNullOrEmpty(text)) { return text; } } catch { } object obj2 = ((settler is Component) ? settler : null); object obj3; if (obj2 == null) { obj3 = null; } else { GameObject gameObject = ((Component)obj2).gameObject; obj3 = ((gameObject != null) ? ((Object)gameObject).name : null); } if (obj3 == null) { obj3 = "resident"; } return (string)obj3; } private static Vector3 HomePosition(object settler) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) try { object obj = _homePositionProperty?.GetValue(settler, null); if (obj is Vector3) { return (Vector3)obj; } } catch { } object obj3 = ((settler is Component) ? settler : null); if (obj3 == null) { return Vector3.zero; } return ((Component)obj3).transform.position; } private static float Distance(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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) float num = a.x - b.x; float num2 = a.z - b.z; return Mathf.Sqrt(num * num + num2 * num2); } private static bool IsLocalPlayer(Humanoid user) { Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val != (Object)null) { return (Object)(object)val == (Object)(object)Player.m_localPlayer; } return false; } private static void Say(string message) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } private static void ZNetViewAwakePostfix(ZNetView __instance) { RegisterStationRpc(__instance); } private static void RegisterStationRpc(ZNetView view) { if ((Object)(object)view == (Object)null || !ViewBelongsToSupportedStation(view)) { return; } int instanceID = ((Object)view).GetInstanceID(); if (!RegisteredStationViews.Add(instanceID)) { return; } try { view.Register<long, bool>("InnLagFix_StationIgnore_104", (Action<long, long, bool>)delegate(long sender, long requesterId, bool ignored) { ApplyStationToggle(view, sender, requesterId, ignored); }); } catch (Exception ex) { RegisteredStationViews.Remove(instanceID); if (!_loggedStationFailure) { _loggedStationFailure = true; _log.LogWarning((object)("[STATION-IGNORE] Could not register station toggle RPC: " + ex.Message)); } } } private static bool StationInteractPrefix(object __instance, Humanoid __0, bool __1, ref bool __result) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!Active || __1 || !ModifierHeld() || !IsLocalPlayer(__0)) { return true; } Component val = (Component)((__instance is Component) ? __instance : null); ZNetView val2 = ViewOf(val); if ((Object)(object)val2 == (Object)null || !val2.IsValid() || !ViewBelongsToSupportedStation(val2)) { return true; } if (!PrivateArea.CheckAccess(val.transform.position, 0f, false, false)) { return true; } if (!CanLocalPlayerManageStation(val2)) { return true; } bool flag = !IsStationIgnored(val2); RequestStationIgnored(val2, flag); Say(StationName(val) + (flag ? " will now be ignored by Innangard." : " is available to Innangard again.")); __result = true; return false; } private static void StationHoverPostfix(object __instance, ref string __result) { if (!Active) { return; } ZNetView val = ViewOf((Component)((__instance is Component) ? __instance : null)); if (!((Object)(object)val == (Object)null) && val.IsValid() && ViewBelongsToSupportedStation(val) && CanLocalPlayerManageStation(val)) { bool flag = IsStationIgnored(val); __result = __result + "\n[<color=yellow><b>" + ModifierLabel() + "</b></color>] " + (flag ? "Use Station" : "Ignore Station"); if (flag) { __result += "\n<color=#d99a76>Ignored by Innangard</color>"; } } } private static void ApplyStationToggle(ZNetView view, long sender, long requesterId, bool ignored) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (!Active || (Object)(object)view == (Object)null || !view.IsValid() || !view.IsOwner()) { return; } try { if (!AuthenticateRequester(sender, requesterId) || !CanRequesterManageStation(view, requesterId)) { _log.LogWarning((object)("[STATION-IGNORE] Rejected unmanaged station toggle for requester=" + requesterId + ".")); return; } ZDO zDO = view.GetZDO(); if (zDO != null) { zDO.Set("inn_lagfix_ignore_station", ignored); if (ignored) { zDO.Set("inn_station_claim", ZDOID.None); zDO.Set("inn_station_claim_until", 0L); } Plugin.ForgetStationLease(view); _log.LogInfo((object)("[STATION-IGNORE] " + StationName(view) + " ignored=" + ignored + " by " + requesterId + ".")); } } catch (Exception ex) { if (!_loggedStationFailure) { _loggedStationFailure = true; _log.LogWarning((object)("[STATION-IGNORE] Toggle failed once: " + ex.GetType().Name + ": " + ex.Message)); } } } private static void CaretakerTargetStillValidPostfix(object __instance, ref bool __result) { if (Active && __result && __instance != null && !(_caretakerTargetField == null)) { object? value = _caretakerTargetField.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val != (Object)null && IsStationIgnored(ViewOf((Component)(object)val.transform))) { __result = false; } } } private static void CookStillWorthDoingPostfix(object __instance, ref bool __result) { if (Active && __result && __instance != null && !(_cookTargetField == null)) { object? value = _cookTargetField.GetValue(__instance); Component val = (Component)((value is Component) ? value : null); if ((Object)(object)val != (Object)null && IsStationIgnored(ViewOf(val))) { __result = false; } } } internal static bool IsSupportedStation(ZNetView view) { return ViewBelongsToSupportedStation(view); } internal static ZNetView GetSupportedStationView(Component component) { ZNetView val = ViewOf(component); if (!ViewBelongsToSupportedStation(val)) { return null; } return val; } internal static Component GetSupportedStationComponent(ZNetView view) { if ((Object)(object)view == (Object)null || !ViewBelongsToSupportedStation(view) || _stationTypes == null) { return null; } Type[] stationTypes = _stationTypes; foreach (Type type in stationTypes) { if (!(type == null)) { Component component = ((Component)view).GetComponent(type); if ((Object)(object)component != (Object)null) { return component; } Component componentInParent = ((Component)view).GetComponentInParent(type); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } Component componentInChildren = ((Component)view).GetComponentInChildren(type, true); if ((Object)(object)componentInChildren != (Object)null) { return componentInChildren; } } } return null; } internal static void RequestStationIgnored(ZNetView view, bool ignored) { if (Active && !((Object)(object)view == (Object)null) && view.IsValid() && ViewBelongsToSupportedStation(view)) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && CanLocalPlayerManageStation(view)) { RegisterStationRpc(view); view.InvokeRPC("InnLagFix_StationIgnore_104", new object[2] { localPlayer.GetPlayerID(), ignored }); } } } internal static bool CanLocalPlayerManageStation(ZNetView view) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { return CanRequesterManageStation(view, localPlayer.GetPlayerID()); } return false; } private static bool AuthenticateRequester(long sender, long requesterId) { if (_networkAuthenticateMethod == null || requesterId == 0L) { return false; } try { object obj = _networkAuthenticateMethod.Invoke(null, new object[3] { sender, requesterId, "station ignore toggle" }); return obj is bool && (bool)obj; } catch { return false; } } private static bool CanRequesterManageStation(ZNetView view, long requesterId) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (requesterId == 0L || (Object)(object)view == (Object)null || !view.IsValid()) { return false; } Component supportedStationComponent = GetSupportedStationComponent(view); if ((Object)(object)supportedStationComponent == (Object)null) { return false; } Piece val = supportedStationComponent.GetComponent<Piece>() ?? supportedStationComponent.GetComponentInParent<Piece>(); if ((Object)(object)val == (Object)null || !val.IsPlacedByPlayer()) { return false; } object obj = FindManagingFrith(supportedStationComponent.transform.position); if (obj == null || _frithCanManageMethod == null) { return false; } try { object obj2 = _frithCanManageMethod.Invoke(obj, new object[1] { requesterId }); if (!(obj2 is bool) || !(bool)obj2) { return false; } return CanRequesterLeadFrith(obj, requesterId); } catch { return false; } } internal static bool CanLocalPlayerStrictlyManageFrith(object frith) { Player localPlayer = Player.m_localPlayer; if (frith == null || (Object)(object)localPlayer == (Object)null || _frithCanManageMethod == null) { return false; } long playerID = localPlayer.GetPlayerID(); try { object obj = _frithCanManageMethod.Invoke(frith, new object[1] { playerID }); return obj is bool && (bool)obj && CanRequesterLeadFrith(frith, playerID); } catch { return false; } } private static void BindStrictLeadershipInternals() { if (_frithType == null) { return; } _strictLeadershipMethods = (from m in _frithType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.ReturnType == typeof(bool) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(long) && m.Name != "CanManage" && LeadershipName(m.Name) select m).ToArray(); List<MethodInfo> list = new List<MethodInfo>(); try { Type[] types = _frithType.Assembly.GetTypes(); foreach (Type type in types) { if (type == null || type.Namespace == null || !type.Namespace.StartsWith("Innangard", StringComparison.Ordinal)) { continue; } MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.ReturnType != typeof(bool)) && LeadershipName(methodInfo.Name)) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 2 && parameters.Any((ParameterInfo p) => p.ParameterType == typeof(long)) && parameters.Any((ParameterInfo p) => p.ParameterType == _frithType || p.ParameterType == typeof(ZDO) || p.ParameterType == typeof(ZNetView))) { list.Add(methodInfo); } } } } } catch (ReflectionTypeLoadException ex) { Type[] types = ex.Types ?? Array.Empty<Type>(); foreach (Type type2 in types) { if (type2 == null || type2.Namespace == null || !type2.Namespace.StartsWith("Innangard", StringComparison.Ordinal)) { continue; } MethodInfo[] methods = type2.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { ParameterInfo[] parameters2 = methodInfo2.GetParameters(); if (methodInfo2.ReturnType == typeof(bool) && LeadershipName(methodInfo2.Name) && parameters2.Length == 2 && parameters2.Any((ParameterInfo p) => p.ParameterType == typeof(long)) && parameters2.Any((ParameterInfo p) => p.ParameterType == _frithType || p.ParameterType == typeof(ZDO) || p.ParameterType == typeof(ZNetView))) { list.Add(methodInfo2); } } } } _staticLeadershipMethods = list.Distinct().ToArray(); List<MemberInfo> list2 = new List<MemberInfo>(); List<MemberInfo> list3 = new List<MemberInfo>(); FieldInfo[] fields = _frithType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (LeadershipName(fieldInfo.Name)) { list2.Add(fieldInfo); } else if (HouseholdName(fieldInfo.Name) || HouseholdName(fieldInfo.FieldType.Name)) { list3.Add(fieldInfo); } } PropertyInfo[] properties = _frithType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.GetIndexParameters().Length == 0 && !(propertyInfo.GetGetMethod(nonPublic: true) == null)) { if (LeadershipName(propertyInfo.Name)) { list2.Add(propertyInfo); } else if (HouseholdName(propertyInfo.Name) || HouseholdName(propertyInfo.PropertyType.Name)) { list3.Add(propertyInfo); } } } _strictLeadershipMembers = list2.ToArray(); _householdMembers = list3.ToArray(); string text = ((_strictLeadershipMethods.Length == 0) ? "none" : string.Join(", ", _strictLeadershipMethods.Select((MethodInfo m) => m.Name).Distinct().ToArray())); string text2 = ((_staticLeadershipMethods.Length == 0) ? "none" : string.Join(", ", _staticLeadershipMethods.Select((MethodInfo m) => m.DeclaringType.Name + "." + m.Name).Distinct().ToArray())); string text3 = ((_strictLeadershipMembers.Length == 0) ? "none" : string.Join(", ", _strictLeadershipMembers.Select((MemberInfo m) => m.Name).Distinct().ToArray())); _log.LogInfo((object)("[MANAGE-PERM] Strict Household leadership binding: methods=" + text + "; static=" + text2 + "; members=" + text3 + ". Founder fallback uses the Frithstone Piece creator.")); } private static bool LeadershipName(string name) { if (string.IsNullOrEmpty(name)) { return false; } string text = name.ToLowerInvariant(); if (!text.Contains("leader") && !text.Contains("founder")) { return text.Contains("creator"); } return true; } private static bool HouseholdName(string name) { if (!string.IsNullOrEmpty(name)) { return name.IndexOf("household", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool CanRequesterLeadFrith(object frith, long requesterId) { if (frith == null || requesterId == 0L) { return false; } Component val = (Component)((frith is Component) ? frith : null); if ((Object)(object)val != (Object)null) { Piece val2 = val.GetComponent<Piece>() ?? val.GetComponentInParent<Piece>(); if ((Object)(object)val2 != (Object)null && val2.GetCreator() == requesterId) { return true; } } MethodInfo[] strictLeadershipMethods = _strictLeadershipMethods; foreach (MethodInfo methodInfo in strictLeadershipMethods) { try { object obj = methodInfo.Invoke(frith, new object[1] { requesterId }); if (obj is bool && (bool)obj) { return true; } } catch { } } strictLeadershipMethods = _staticLeadershipMethods; foreach (MethodInfo methodInfo2 in strictLeadershipMethods) { try { object[] array = BuildStaticLeadershipArgs(methodInfo2, frith, requesterId); if (array != null) { object obj3 = methodInfo2.Invoke(null, array); if (obj3 is bool && (bool)obj3) { return true; } } } catch { } } MemberInfo[] strictLeadershipMembers = _strictLeadershipMembers; foreach (MemberInfo member in strictLeadershipMembers) { try { if (ValueContainsPlayerId(ReadMember(frith, member), requesterId, 0)) { return true; } } catch { } } strictLeadershipMembers = _householdMembers; foreach (MemberInfo member2 in strictLeadershipMembers) { try { if (HouseholdContainsLeader(ReadMember(frith, member2), requesterId, 0)) { return true; } } catch { } } if (!_loggedLeadershipFallback) { _loggedLeadershipFallback = true; _log.LogWarning((object)"[MANAGE-PERM] No Household Leader match was found for a non-founder request; management denied (fail closed). SharedAccess/ward membership alone is never enough."); } return false; } private static object[] BuildStaticLeadershipArgs(MethodInfo method, object frith, long requesterId) { if (method == null || frith == null) { return null; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 2) { return null; } Component val = (Component)((frith is Component) ? frith : null); ZNetView val2 = (((Object)(object)val != (Object)null) ? (val.GetComponent<ZNetView>() ?? val.GetComponentInParent<ZNetView>()) : null); ZDO val3 = (((Object)(object)val2 != (Object)null && val2.IsValid()) ? val2.GetZDO() : null); object[] array = new object[2]; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType == typeof(long)) { array[i] = requesterId; continue; } if (parameterType.IsInstanceOfType(frith)) { array[i] = frith; continue; } if (parameterType == typeof(ZNetView)) { array[i] = val2; continue; } if (parameterType == typeof(ZDO)) { array[i] = val3; continue; } return null; } return array; } private static object ReadMember(object instance, MemberInfo member) { FieldInfo fieldInfo = member as FieldInfo; if (fieldInfo != null) { return fieldInfo.GetValue(instance); } PropertyInfo propertyInfo = member as PropertyInfo; if (!(propertyInfo != null)) { return null; } return propertyInfo.GetValue(instance, null); } private static bool HouseholdContainsLeader(object household, long requesterId, int depth) { if (household == null || depth > 2) { return false; } IEnumerable enumerable = household as IEnumerable; if (!(household is string) && enumerable != null) { foreach (object item in enumerable) { if (HouseholdEntryIsLeader(item, requesterId)) { return true; } } } Type type = household.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { object value = fieldInfo.GetValue(household); if (LeadershipName(fieldInfo.Name) && ValueContainsPlayerId(value, requesterId, 0)) { return true; } if (HouseholdName(fieldInfo.Name) && value != household && HouseholdContainsLeader(value, requesterId, depth + 1)) { return true; } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.GetIndexParameters().Length != 0 || propertyInfo.GetGetMethod(nonPublic: true) == null) { continue; } try { object value2 = propertyInfo.GetValue(household, null); if (LeadershipName(propertyInfo.Name) && ValueContainsPlayerId(value2, requesterId, 0)) { return true; } if (HouseholdName(propertyInfo.Name) && value2 != household && HouseholdContainsLeader(value2, requesterId, depth + 1)) { return true; } } catch { } } return HouseholdEntryIsLeader(household, requesterId); } private static bool HouseholdEntryIsLeader(object entry, long requesterId) { if (entry == null) { return false; } Type type = entry.GetType(); bool flag = false; bool flag2 = false; FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { object value; try { value = fieldInfo.GetValue(entry); } catch { continue; } string text = fieldInfo.Name.ToLowerInvariant(); if (LeadershipName(text)) { if (value is bool) { flag |= (bool)value; } else if (ValueContainsPlayerId(value, requesterId, 0)) { return true; } } if (text.Contains("player") || text.Contains("id")) { flag2 |= ValueContainsPlayerId(value, requesterId, 0); } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.GetIndexParameters().Length != 0 || propertyInfo.GetGetMethod(nonPublic: true) == null) { continue; } object value2; try { value2 = propertyInfo.GetValue(entry, null); } catch { continue; } string text2 = propertyInfo.Name.ToLowerInvariant(); if (LeadershipName(text2)) { if (value2 is bool) { flag |= (bool)value2; } else if (ValueContainsPlayerId(value2, requesterId, 0)) { return true; } } if (text2.Contains("player") || text2.Contains("id")) { flag2 |= ValueContainsPlayerId(value2, requesterId, 0); } } return flag && flag2; } private static bool ValueContainsPlayerId(object value, long requesterId, int depth) { if (value == null || depth > 2) { return false; } if (value is long) { return (long)value == requesterId; } if (value is int) { return (int)value == requesterId; } if (value is ulong) { return (ulong)value == (ulong)requesterId; } if (value is string text) { if (long.TryParse(text.Trim(), out var result)) { return result == requesterId; } char[] separator = new char[9] { ',', ';', '|', ' ', '\t', '\r', '\n', ':', '=' }; string[] array = text.Split(separator, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { if (long.TryParse(array[i], out result) && result == requesterId) { return true; } } return false; } if (value is IEnumerable enumerable) { foreach (object item in enumerable) { if (ValueContainsPlayerId(item, requesterId, depth + 1)) { return true; } } return false; } Type type = value.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { string text2 = fieldInfo.Name.ToLowerInvariant(); if ((text2.Contains("player") || text2.Contains("id") || LeadershipName(text2)) && ValueContainsPlayerId(fieldInfo.GetValue(value), requesterId, depth + 1)) { return true; } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.GetIndexParameters().Length != 0 || propertyInfo.GetGetMethod(nonPublic: true) == null) { continue; } string text3 = propertyInfo.Name.ToLowerInvariant(); if (!text3.Contains("player") && !text3.Contains("id") && !LeadershipName(text3)) { continue; } try { if (ValueContainsPlayerId(propertyInfo.GetValue(value, null), requesterId, depth + 1)) { return true; } } catch { } } return false; } private static object FindManagingFrith(Vector3 position) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (_frithInstancesField == null || _frithCoversPointMethod == null) { return null; } if (!(_frithInstancesField.GetValue(null) is IEnumerable enumerable)) { return null; } object result = null; float num = float.MaxValue; foreach (object item in enumerable) { Component val = (Component)((item is Component) ? item : null); if ((Object)(object)val == (Object)null || !val.gameObject.activeInHierarchy) { continue; } try { object obj = _frithCoversPointMethod.Invoke(item, new object[2] { position, 18f }); if (!(obj is bool) || !(bool)obj) { continue; } goto IL_00b3; } catch { } continue; IL_00b3: float num2 = Vector3.Distance(val.transform.position, position); if (num2 < num) { num = num2; result = item; } } return result; } private static bool ViewBelongsToSupportedStation(ZNetView view) { if ((Object)(object)view == (Object)null || _stationTypes == null) { return false; } Type[] stationTypes = _stationTypes; foreach (Type type in stationTypes) { if (!(type == null) && ((Object)(object)((Component)view).GetComponent(type) != (Object)null || (Object)(object)((Component)view).GetComponentInParent(type) != (Object)null || (Object)(object)((Component)view).GetComponentInChildren(type, true) != (Object)null)) { return true; } } return false; } private static ZNetView ViewOf(Component component) { if ((Object)(object)component == (Object)null) { return null; } return component.GetComponent<ZNetView>() ?? component.GetComponentInParent<ZNetView>() ?? component.GetComponentInChildren<ZNetView>(true); } private static string StationName(Component component) { if ((Object)(object)component == (Object)null) { return "Station"; } Piece val = component.GetComponent<Piece>() ?? component.GetComponentInParent<Piece>(); if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(val.m_name)) { return val.m_name; } if (!((Object)(object)component.gameObject != (Object)null)) { return "Station"; } return ((Object)component.gameObject).name; } private static string StationName(ZNetView view) { return StationName((Component)(object)view); } } internal static class BetterOrganisationIntegration { private static ConfigEntry<bool> _enabled; private static Harmony _harmony; private static bool _present; private static bool _rulesInstalled; private static bool _uiInstalled; private static float _nextRefresh; internal static ManualLogSource Log { get; private set; } internal static bool Active { get { if (Plugin.Enabled != null && Plugin.Enabled.Value && _present && _enabled != null) { return _enabled.Value; } return false; } } internal static void Initialize(ConfigFile config, ManualLogSource log, Harmony harmony) { Log = log; _harmony = harmony; _enabled = config.Bind<bool>("Better Organisation", "IntegrateWithInnangard", true, "When Better Organisation is installed, use its category/item destination rules for Innangard sorting and replace Innangard's redundant chest-rules material picker (Shift+E by default) on BO-managed chests with an Open Better Organisation button."); _present = AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => string.Equals(a.GetName().Name, "ChestCategories", StringComparison.OrdinalIgnoreCase)); if (!_present) { Log.LogInfo((object)"[BO] Better Organisation not installed; BO-specific Innangard integration skipped."); return; } BetterOrganisationRules.Bind(); BetterOrganisationDrawerPriority.Initialize(harmony); InstallPatches(); BetterOrganisationRules.Refresh(forceSummary: true); } internal static void Tick() { if (Active && !(Time.unscaledTime < _nextRefresh)) { _nextRefresh = Time.unscaledTime + 0.5f; InstallPatches(); BetterOrganisationRules.Refresh(forceSummary: false); } } internal static void Shutdown() { if (_present) { BetterOrganisationRules.RestoreAll(); } } private static void InstallPatches() { if (_harmony != null && Active) { if (!_rulesInstalled) { _rulesInstalled = BetterOrganisationRules.Install(_harmony); } if (!_uiInstalled) { _uiInstalled = BetterOrganisationChestPanelCompat.Install(_harmony); } } } internal static string Root(Exception e) { while (e is TargetInvocationException && e.InnerException != null) { e = e.InnerException; } if (e != null) { return e.ToString(); } return "unknown error"; } } internal static class BetterOrganisationDrawerPriority { private sealed class Query { internal Vector3 Centre; internal float Radius; internal float Seen; internal List<object> Targets = new List<object>(); } private static readonly List<Query> Recent = new List<Query>(); private static MethodInfo _findTargets; private static PropertyInfo _home; private static PropertyInfo _scanRadius; private static PropertyInfo _targetValid; private static PropertyInfo _targetView; private static MethodInfo _itemTemplate; private static MethodInfo _externalTryGetReal; private static MethodInfo _externalGetFreeSpace; private static bool _installed; internal static void Initialize(Harmony harmony) { //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown if (_installed || harmony == null) { return; } Type type = AccessTools.TypeByName("Innangard.SettlerController"); Type type2 = AccessTools.TypeByName("Innangard.ItemDrawerBridge"); if (!(type == null) && !(type2 == null)) { _findTargets = AccessTools.Method(type2, "FindTargets", (Type[])null, (Type[])null); _home = AccessTools.Property(type, "Home"); _scanRadius = AccessTools.Property(type, "SettlementScanRadius"); Type nestedType = type2.GetNestedType("Target", BindingFlags.Public | BindingFlags.NonPublic); if (nestedType != null) { _targetValid = AccessTools.Property(nestedType, "IsValid"); _targetView = AccessTools.Property(nestedType, "View"); _itemTemplate = AccessTools.Method(nestedType, "ItemTemplate", (Type[])null, (Type[])null); } Type type3 = AccessTools.TypeByName("InnangardBetrValheimDrawerBridge.Bridge"); if (type3 != null) { _externalTryGetReal = AccessTools.Method(type3, "TryGetReal", (Type[])null, (Type[])null); _externalGetFreeSpace = AccessTools.Method(type3, "GetFreeSpace", (Type[])null, (Type[])null); } if (_findTargets == null || _home == null || _scanRadius == null || _targetValid == null || _itemTemplate == null) { BetterOrganisationIntegration.Log.LogWarning((object)"[BO] Could not bind Innangard drawer scan context; BO rules still work but transient drawer-first fallback protection is unavailable."); return; } harmony.Patch((MethodBase)_findTargets, (HarmonyMethod)null, new HarmonyMethod(typeof(BetterOrganisationDrawerPriority), "FindTargetsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _installed = true; BetterOrganisationIntegration.Log.LogInfo((object)"[BO] Drawer-first destination guard now follows Innangard's own recent ItemDrawerBridge.FindTargets scans."); } } private static void FindTargetsPostfix(object __0, object __result) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if (__0 == null) { return; } try { Vector3 centre = (Vector3)_home.GetValue(__0, null); float radius = Convert.ToSingle(_scanRadius.GetValue(__0, null)); List<object> list = new List<object>(); if (__result is IEnumerable enumerable) { foreach (object item in enumerable) { if (item != null) { list.Add(item); } } } float now = Time.unscaledTime; Recent.RemoveAll((Query q) => q == null || now - q.Seen > 3f); Query query = Recent.FirstOrDefault((Query q) => Vector3.Distance(q.Centre, centre) < 1f && Mathf.Abs(q.Radius - radius) < 1f); if (query == null) { query = new Query(); Recent.Add(query); } query.Centre = centre; query.Radius = radius; query.Seen = now; query.Targets = list; while (Recent.Count > 8) { Recent.Remove(Recent.OrderBy((Query q) => q.Seen).First()); } } catch (Exception e) { BetterOrganisationIntegration.Log.LogWarning((object)("[BO] Could not remember Innangard drawer scan: " + BetterOrganisationIntegration.Root(e))); } } internal static bool MatchingDrawerBeforeBo(Container chest, string sharedName) { if (!_installed || (Object)(object)chest == (Object)null || string.IsNullOrEmpty(sharedName)) { return false; } float now = Time.unscaledTime; Query query = (from q in Recent where q != null && now - q.Seen <= 2f && Vector3.Distance(((Component)chest).transform.position, q.Centre) <= q.Radius + 10f orderby Vector3.Distance(((Component)chest).transform.position, q.Centre) select q).FirstOrDefault(); if (query == null) { return false; } foreach (object target in query.Targets) { if (UsableMatchingTarget(target, sharedName)) { return true; } } return false; } private static bool UsableMatchingTarget(object target, string sharedName) { try { object value = _targetValid.GetValue(target, null); if (!(value is bool) || !(bool)value) { return false; } object? obj = _itemTemplate.Invoke(target, null); ItemData val = (ItemData)((obj is ItemData) ? obj : null); if (val?.m_shared == null || !string.Equals(val.m_shared.m_name, sharedName, StringComparison.Ordinal)) { return false; } if (_externalTryGetReal != null && _externalGetFreeSpace != null && _targetView != null) { object? value2 = _targetView.GetValue(target, null); ZNetView val2 = (ZNetView)((value2 is ZNetView) ? value2 : null); if ((Object)(object)val2 != (Object)null) { object[] array = new object[2] { val2, null }; object obj2 = _externalTryGetReal.Invoke(null, array); if (obj2 is bool && (bool)obj2 && array[1] != null) { return Convert.ToInt32(_externalGetFreeSpace.Invoke(null, new object[1] { array[1] })) > 0; } } } return true; } catch { return false; } } } internal static class BetterOrganisationChestPanelCompat { private const BindingFlags InstanceAny = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags StaticAny = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private const string CompatObjectName = "pho_bo_compat_note"; private const string CompatButtonObjectName = "pho_bo_compat_button"; private const string CompatText = "Override: Storage Rules managed by Better Organisation"; private const string CompatButtonText = "Open Better Organisation"; [ThreadStatic] private static bool _inPanelRead; private static bool _installed; private static bool _reportedMissing; private static bool _reportedSuppression; private static FieldInfo _container; private static FieldInfo _picking; private static FieldInfo _column; private static FieldInfo _grid; private static FieldInfo _choices; private static FieldInfo _mineHelp; private static FieldInfo _origin; private static FieldInfo _byHand; private static FieldInfo _slack; private static FieldInfo _remeasureFlag; private static MethodInfo _remeasure; private static MethodInfo _resize; private static PropertyInfo _boUiInstance; private static PropertyInfo _boGui; private static MethodInfo _boToggleEditor; internal static bool InPanelRead => _inPanelRead; internal static bool Install(Harmony harmony) { //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Expected O, but got Unknown //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Expected O, but got Unknown //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Expected O, but got Unknown //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Expected O, but got Unknown //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Expected O, but got Unknown if (_installed) { return true; } if (!BetterOrganisationRules.IsAvailable) { return false; } Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "Innangard", StringComparison.OrdinalIgnoreCase)); Type type = assembly?.GetType("Innangard.ChestSortPanel", throwOnError: false); if (type == null) { if (!_reportedMissing && assembly != null) { _reportedMissing = true; BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Innangard.ChestSortPanel was not found; chest-rules picker suppression is unavailable."); } return false; } MethodInfo method = type.GetMethod("Open", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Container) }, null); MethodInfo method2 = type.GetMethod("Refresh", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); MethodInfo methodInfo = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo m) { if (m.Name != "BuildChoices") { return false; } ParameterInfo[] parameters = m.GetParameters(); return parameters.Length == 2 && typeof(Container).IsAssignableFrom(parameters[0].ParameterType); }); MethodInfo methodInfo2 = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Populate" && m.GetParameters().Length == 1 && m.ReturnType == typeof(void)); _container = type.GetField("_container", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _picking = type.GetField("_picking", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _column = type.GetField("_column", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _grid = type.GetField("_grid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _choices = type.GetField("_choices", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _mineHelp = type.GetField("_mineHelp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _origin = type.GetField("_origin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _byHand = type.GetField("_byHand", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _slack = type.GetField("_slack", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _remeasureFlag = type.GetField("_remeasure", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _remeasure = type.GetMethod("Remeasure", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); _resize = type.GetMethod("Resize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); Type? obj = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "ChestCategories", StringComparison.OrdinalIgnoreCase))?.GetType("ChestCategories.UI.ModUi", throwOnError: false); _boUiInstance = obj?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _boGui = obj?.GetProperty("Gui", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _boToggleEditor = obj?.GetMethod("ToggleEditor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Container) }, null); if (method == null || method2 == null || methodInfo == null || methodInfo2 == null || _container == null || _picking == null || _column == null || _mineHelp == null) { if (!_reportedMissing) { _reportedMissing = true; BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Innangard 0.1.9 chest-rules panel binding incomplete: " + $"Open={method != null} Refresh={method2 != null} BuildChoices={methodInfo != null} " + $"Populate={methodInfo2 != null} container={_container != null} picking={_picking != null} column={_column != null} mineHelp={_mineHelp != null}.")); } return false; } HarmonyMethod val = new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PanelScopePrefix", (Type[])null); HarmonyMethod val2 = new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PanelScopePostfix", (Type[])null); HarmonyMethod val3 = new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PanelScopeFinalizer", (Type[])null); harmony.Patch((MethodBase)method, val, val2, (HarmonyMethod)null, val3, (HarmonyMethod)null); harmony.Patch((MethodBase)method2, val, val2, (HarmonyMethod)null, val3, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "BuildChoicesPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PopulatePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _installed = true; BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Bound Innangard.ChestSortPanel Open/Refresh/BuildChoices/Populate."); BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] BO-managed Innangard chest-rules panels keep intake/private controls and replace only the material picker with a Better Organisation storage-rules shortcut."); if (_boUiInstance != null && _boToggleEditor != null) { BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Better Organisation category editor shortcut bound."); } else { BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Better Organisation category editor shortcut was not found; the compatibility heading will still be shown."); } return true; } private static void PanelScopePrefix() { _inPanelRead = true; } private static void PanelScopePostfix(object __instance) { _inPanelRead = false; Apply(__instance); } private static Exception PanelScopeFinalizer(Exception __exception) { _inPanelRead = false; return __exception; } private static bool BuildChoicesPrefix(Container __0) { return !BetterOrganisationRules.IsManaged(__0); } private static bool PopulatePrefix(object __instance) { if (!BetterOrganisationRules.IsManaged(GetContainer(__instance))) { return true; } ClearPickerRows(__instance); return false; } private static Container GetContainer(object panel) { try { return (Container)((panel != null) ? /*isinst with value type is only supported in some contexts*/: null); } catch { return null; } } private static void ClearPickerRows(object panel) { try { object? obj = _grid?.GetValue(panel); RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null); if ((Object)(object)val != (Object)null) { for (int num = ((Transform)val).childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)((Transform)val).GetChild(num)).gameObject); } } (_choices?.GetValue(panel) as IList)?.Clear(); } catch (Exception e) { BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not clear Innangard's old material rows: " + BetterOrganisationIntegration.Root(e))); } } private static void Apply(object panel) { if (panel == null) { return; } try { Container container = GetContainer(panel); bool flag = BetterOrganisationRules.IsManaged(container); object? value = _picking.GetValue(panel); RectTransform val = (RectTransform)((value is RectTransform) ? value : null); object? value2 = _column.GetValue(panel); RectTransform val2 = (RectTransform)((value2 is RectTransform) ? value2 : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return; } GameObject val3 = FindCompatObject(val2, "pho_bo_compat_note"); GameObject val4 = FindCompatObject(val2, "pho_bo_compat_button"); bool flag2 = false; if (flag) { if (((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); flag2 = true; } if ((Object)(object)val3 == (Object)null) { val3 = CreateCompatNote(panel, val2, val); flag2 = (Object)(object)val3 != (Object)null; } if ((Object)(object)val4 == (Object)null && _boUiInstance != null && _boToggleEditor != null) { val4 = CreateCompatButton(panel, val2, val, container); flag2 = (Object)(object)val4 != (Object)null; } if ((Object)(object)val3 != (Object)null) { if (!val3.activeSelf) { val3.SetActive(true); flag2 = true; } int siblingIndex = ((Transform)val).GetSiblingIndex(); if (val3.transform.GetSiblingIndex() != siblingIndex) { val3.transform.SetSiblingIndex(siblingIndex); flag2 = true; } } if ((Object)(object)val4 != (Object)null) { BetterOrganisationEditorButtonAction component = val4.GetComponent<BetterOrganisationEditorButtonAction>(); if ((Object)(object)component != (Object)null) { component.Target = container; component.InnangardPanel = panel; } if (!val4.activeSelf) { val4.SetActive(true); flag2 = true; } int num = (((Object)(object)val3 != (Object)null) ? Math.Min(val3.transform.GetSiblingIndex() + 1, Math.Max(0, ((Transform)val2).childCount - 1)) : ((Transform)val).GetSiblingIndex()); if (val4.transform.GetSiblingIndex() != num) { val4.transform.SetSiblingIndex(num); flag2 = true; } } ClearPickerRows(panel); SetSlackFlexible(panel, 1f); if (!_reportedSuppression) { _reportedSuppression = true; BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Suppressed the Innangard chest-rules Search/material list for a Better Organisation-managed chest."); } } else { if ((Object)(object)val3 != (Object)null && val3.activeSelf) { val3.SetActive(false); flag2 = true; } if ((Object)(object)val4 != (Object)null && val4.activeSelf) { val4.SetActive(false); flag2 = true; } } if (flag2) { if (_remeasureFlag != null) { _remeasureFlag.SetValue(panel, true); } _remeasure?.Invoke(panel, null); _resize?.Invoke(panel, null); } } catch (Exception e) { BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not apply chest-rules material-picker compatibility layout: " + BetterOrganisationIntegration.Root(e))); } } private static GameObject FindCompatObject(RectTransform column, string name) { for (int i = 0; i < ((Transform)column).childCount; i++) { Transform child = ((Transform)column).GetChild(i); if ((Object)(object)child != (Object)null && (Object)(object)((Component)child).gameObject != (Object)null && ((Object)((Component)child).gameObject).name == name) { return ((Component)child).gameObject; } } return null; } private static GameObject CreateCompatNote(object panel, RectTransform column, RectTransform picking) { object? obj = _origin?.GetValue(panel); Component val = (Component)((obj is Component) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null) { object? obj2 = _mineHelp?.GetValue(panel); val = (Component)((obj2 is Component) ? obj2 : null); } if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null) { return null; } GameObject obj3 = Object.Instantiate<GameObject>(val.gameObject); ((Object)obj3).name = "pho_bo_compat_note"; obj3.transform.SetParent((Transform)(object)column, false); obj3.transform.SetSiblingIndex(((Transform)picking).GetSiblingIndex()); Component component = obj3.GetComponent(((object)val).GetType()); SetText(component, "Override: Storage Rules managed by Better Organisation"); SetNumericProperty(component, "fontSize", 20); obj3.SetActive(true); return obj3; } private static GameObject CreateCompatButton(object panel, RectTransform column, RectTransform picking, Container container) { object? obj = _byHand?.GetValue(panel); Component val = (Component)((obj is Component) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null) { return null; } GameObject val2 = Object.Instantiate<GameObject>(val.gameObject); ((Object)val2).name = "pho_bo_compat_button"; val2.transform.SetParent((Transform)(object)column, false); val2.transform.SetSiblingIndex(((Transform)picking).GetSiblingIndex()); SetFirstChildText(val2, "Open Better Organisation"); Component component = val2.GetComponent(((object)val).GetType()); object obj2 = ((object)component)?.GetType().GetProperty("onClick", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(component, null); if (obj2 == null) { Object.Destroy((Object)(object)val2); return null; } obj2.GetType().GetMethod("RemoveAllListeners", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null)?.Invoke(obj2, null); BetterOrganisationEditorButtonAction betterOrganisationEditorButtonAction = val2.AddComponent<BetterOrganisationEditorButtonAction>(); betterOrganisationEditorButtonAction.Target = container; betterOrganisationEditorButtonAction.InnangardPanel = panel; MethodInfo method = typeof(BetterOrganisationEditorButtonAction).GetMethod("Click", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = obj2.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "AddListener" && m.GetParameters().Length == 1); if (method == null || methodInfo == null) { Object.Destroy((Object)(object)val2); return null; } Delegate obj3 = Delegate.CreateDelegate(methodInfo.GetParameters()[0].ParameterType, betterOrganisationEditorButtonAction, method); methodInfo.Invoke(obj2, new object[1] { obj3 }); val2.SetActive(true); return val2; } private static void SetFirstChildText(GameObject root, string value) { if (!((Object)(object)root == (Object)null)) { Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true); for (int i = 0; i < componentsInChildren.Length && !SetText(componentsInChildren[i], value); i++) { } } } private static bool SetText(Component component, string value) { if ((Object)(object)component == (Object)null) { return false; } try { PropertyInfo property = ((object)component).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || !property.CanWrite || property.PropertyType != typeof(string)) { return false; } property.SetValue(component, value, null); return true; } catch { return false; } } private static void SetNumericProperty(Component component, string name, int value) { if ((Object)(object)component == (Object)null) { return; } try { PropertyInfo property = ((object)component).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(property == null) && property.CanWrite) { if (property.PropertyType == typeof(int)) { property.SetValue(component, value, null); } else if (property.PropertyType == typeof(float)) { property.SetValue(component, (float)value, null); } } } catch { } } internal static void CloseInnangardPanel(object panel) { if (panel == null) { return; } try { Type type = panel.GetType(); MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => (m.Name == "Close" || m.Name == "Hide" || m.Name == "Dismiss") && m.GetParameters().Length == 0 && m.ReturnType == typeof(void)); if (methodInfo != null) { methodInfo.Invoke(panel, null); BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation."); return; } string[] array = new string[4] { "m_panel", "_panel", "_root", "m_root" }; foreach (string name in array) { object obj = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(panel); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (val != null) { val.SetActive(false); BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation."); return; } Component val2 = (Component)((obj is Component) ? obj : null); if (val2 != null && (Object)(object)val2.gameObject != (Object)null) { val2.gameObject.SetActive(false); BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation."); return; } } Component val3 = (Component)((panel is Component) ? panel : null); if (val3 != null && (Object)(object)val3.gameObject != (Object)null) { val3.gameObject.SetActive(false); BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation."); } else { BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Could not find Innangard's panel root to close it."); } } catch (Exception e) { BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not close Innangard chest-rules panel: " + BetterOrganisationIntegration.Root(e))); } } internal static void OpenBetterOrganisationEditor(Container container) { if ((Object)(object)container == (Object)null || _boUiInstance == null || _boToggleEditor == null) { return; } try { object value = _boUiInstance.GetValue(null, null); if (value == null) { BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Better Organisation UI is not ready yet."); return; } bool flag = false; MethodInfo method = typeof(InventoryGui).GetMethod("IsVisible", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null) { flag = (bool)method.Invoke(null, null); } if (!flag) { object obj = _boGui?.GetValue(value, null); (obj?.GetType().GetMethod("Show", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(Container), typeof(int) }, null))?.Invoke(obj, new object[2] { null, 1 }); } _boToggleEditor.Invoke(value, new object[1] { container }); BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Opened Better Organisation storage rules for the current chest."); } catch (Exception e) { BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not open Better Organisation storage rules: " + BetterOrganisationIntegration.Root(e))); } } private static void SetSlackFlexible(object panel, float value) { try { object obj = _slack?.GetValue(panel); (obj?.GetType().GetProperty("flexibleHeight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.SetValue(obj, value, null); } catch { } } } internal sealed class BetterOrganisationEditorButtonAction : MonoBehaviour { internal Container Target; internal object InnangardPanel; public void Click() { BetterOrganisationChestPanelCompat.CloseInnangardPanel(InnangardPanel); BetterOrganisationChestPanelCompat.OpenBetterOrganisationEditor(Target); } } internal static class BetterOrganisationRules { private sealed class RuleCache { internal string Signature; internal bool HasAnyRule; internal HashSet<string> Accepted; } private sealed class RuleSnapshot { internal bool HasLinks; internal bool AcceptsEverything; internal bool AcceptsStash = true; internal readonly HashSet<string> Include = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal readonly HashSet<string> Exclude = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal bool HasAnyRule { get { if (!HasLinks && !AcceptsEverything && AcceptsStash && Include.Count <= 0) { return Exclude.Count > 0; } return true; } } } private const BindingFlags Any = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private const string MirrorKey = "pho_bo_inn_mirror"; private const string BackupConfiguredKey = "pho_bo_inn_b_cfg"; private const string BackupKindsKey = "pho_bo_inn_b_kinds"; private const string BackupItemsKey = "pho_bo_inn_b_items"; private const string BackupLegacyKindKey = "pho_bo_inn_b_legacy"; private static Assembly _assembly; private static Type _storeType; private static Type _configType; private static Type _categoryServiceType; private static Type _categoryType; private static Type _groupType; private static MethodInfo _getConfig; private static MethodInfo _getCategory; private static PropertyInfo _hasLinks; private static PropertyInfo _links; private static PropertyInfo _includeItems; private static PropertyInfo _excludeItems; private static PropertyInfo _acceptsEverything; private static PropertyInfo _acceptsStash; private static MethodInfo _isLinkedCategory; private static MethodInfo _isLinkedGroup; private static PropertyInfo _categoryGroup; private static PropertyInfo _categoryId; private static PropertyInfo _groupId; private static MethodInfo _serializeConfig; private static readonly Dictionary<int, RuleCache> RuleCaches = new Dictionary<int, RuleCache>(); private static bool _bound; private static bool _reportedUnavailable; private static bool _installed; private static bool _reportedMissing; private static int _lastActive = -1; internal static bool IsAvailable => _bound; internal static bool Install(Harmony harmony) { //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Expected O, but got Unknown //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Expected O, but got Unknown //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Expected O, but got Unknown //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Expected O, but got Unknown //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Expected O, but got Unknown //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Expected O, but got Unknown if (!_bound) { return false; } if (_installed) { return true; } Type type = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "Innangard", StringComparison.OrdinalIgnoreCase))?.GetType("Innangard.ChestSortRules", throwOnError: false); if (type == null) { return false; } BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; Type[] types = new Type[1] { typeof(Container) }; MethodInfo method = type.GetMethod("IsConfigured", bindingAttr, null, types, null); MethodInfo method2 = type.GetMethod("KindsOf", bindingAttr, null, types, null); MethodInfo method3 = type.GetMethod("ReadItems", bindingAttr, null, types, null); Type[] types2 = new Type[2] { typeof(Container), typeof(string) }; MethodInfo method4 = type.GetMethod("Accepts", bindingAttr, null, types2, null); MethodInfo method5 = type.GetMethod("Precision", bindingAttr, null, types2, null); MethodInfo method6 = type.GetMethod("IsSortable", bindingAttr, null, new Type[1] { typeof(ItemData) }, null); if (method == null || method.ReturnType != typeof(bool) || method2 == null || method2.ReturnType != typeof(int) || method3 == null || method3.ReturnType != typeof(HashSet<string>) || method4 == null || method4.ReturnType != typeof(bool) || method5 == null || method5.ReturnType != typeof(int)) { if (!_reportedMissing) { _reportedMissing = true; BetterOrganisationIntegration.Log.LogError((object)"[BO] Innangard chest rule methods changed; local BO matching is unavailable."); } return false; } harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(BetterOrganisationRules), "ConfiguredPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)method2, new HarmonyMethod(typeof(BetterOrganisationRules), "KindsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)method3, new HarmonyMethod(typeof(BetterOrganisationRules), "ItemsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)method4, new HarmonyMethod(typeof(BetterOrganisationRules), "AcceptsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)method5, new HarmonyMethod(typeof(BetterOrganisationRules), "PrecisionPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (method6 != null && method6.ReturnType == typeof(bool)) { harmony.Patch((MethodBase)method6, (HarmonyMethod)null, new HarmonyMethod(typeof(BetterOrganisationRules), "SortablePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); BetterOrganisationIntegration.Log.LogInfo((object)"[BO] BO-explicit destination items are eligible for caretaker chest sorting even when Innangard's native item-type whitelist excludes them; loose-ground pickup remains unchanged."); } else { BetterOrganisationIntegration.Log.LogWarning((object)"[BO] Innangard ChestSortRules.IsSortable(ItemData) was not found; BO-explicit nonstandard item types will keep Innangard's native sorting restriction."); } _installed = true; BetterOrganisationIntegration.Log.LogInfo((object)"[BO] Innangard now reads BO category/item rules locally; no extra rule list is written to chests."); return true; } private static bool ConfiguredPrefix(Container __0, ref bool __result) { if (!TryGetAccepted(__0, out var _)) { return true; } __result = true; return false; } private static bool KindsPrefix(Container __0, ref int __result) { if (!TryGetAccepted(__0, out var _)) { return true; } __result = 0; return false; } private static bool ItemsPrefix(Container __0, ref HashSet<string> __result) { if (!TryGetAccepted(__0, out var accepted)) { return true; } if (BetterOrganisationChestPanelCompat.InPanelRead) { __result = new HashSet<string>(StringComparer.Ordinal) { "__pho_bo_managed__" }; return false; } __result = new HashSet<string>(accepted, StringComparer.Ordinal); return false; } private static bool AcceptsPrefix(Container __0, string __1, ref bool __result) { if (TryGetAccepted(__0, out var accepted)) { __result = !string.IsNullOrEmpty(__1) && accepted.Contains(__1); return false; } if (!HasNativeExplicitRule(__0) && AnyManagedChestAccepts(__1)) { __result = false; return false; } return true; } private static bool PrecisionPrefix(Container __0, string __1, ref int __result) { if (!TryGetAccepted(__0, out var accepted)) { if (!HasNativeExplicitRule(__0) && AnyManagedChestAccepts(__1)) { __result = int.MaxValue; return false; } return true; } if (string.IsNullOrEmpty(__1) || !accepted.Contains(__1)) { __result = int.MaxValue; return false; } if (BetterOrganisationDrawerPriority.MatchingDrawerBeforeBo(__0, __1)) { __result = int.MaxValue; return false; } __result = 0; return false; } private static void SortablePostfix(ItemData __0, ref bool __result) { if (!__result && BetterOrganisationIntegration.Active && __0?.m_shared != null && !__0.m_shared.m_questItem && !__0.m_equipped) { string name = __0.m_shared.m_name; if (!string.IsNullOrEmpty(name) && AnyManagedChestAccepts(name)) { __result = true; } } } private static bool AnyManagedChestAccepts(string sharedName) { if (!_installed || !_bound || string.IsNullOrEmpty(sharedName)) { return false; } foreach (RuleCache value in RuleCaches.Values) { if (value != null && value.HasAnyRule && value.Accepted != null && value.Accepted.Contains(sharedName)) { return true; } } return false; } private static bool HasNativeExplicitRule(Container container) { try { ZNetView containerView = GetContainerView(container); if ((Object)(object)containerView == (Object)null || !containerView.IsValid()) { return false; } ZDO zDO = containerView.GetZDO(); if (zDO == null) { return false; } if (zDO.GetBool("inn_sort_configured", false)) { return true; } if (zDO.GetInt("inn_sort_kinds", 0) != 0) { return true; } return zDO.GetInt("inn_chest_sort_kind", 0) != 0; } catch { return false; } } internal static bool IsManaged(Container container) { HashSet<string> accepted; return TryGetAccepted(container, out accepted); } private static bool TryGetAccepted(Container container, out HashSet<string> accepted) { accepted = null; if (!BetterOrganisationIntegration.Active || !_installed || !_bound || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)container == (Object)null) { return false; } ZNetView containerView = GetContainerView(container); if ((Object)(object)containerView == (Object)null || !containerView.IsValid() || containerView.GetZDO() == null) { return false; } int instanceID = ((Object)containerView).GetInstanceID(); if (!RuleCaches.TryGetValue(instanceID, out var value)) { value = RefreshCac