using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [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("Empress")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EmpressShopkeeperClientLock")] [assembly: AssemblyTitle("EmpressShopkeeperClientLock")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EmpressShopkeeperClientLock { [BepInPlugin("empress.repo.shopkeeperclientlock", "Empress Shopkeeper Client Lock", "1.0.0")] public sealed class EmpressShopkeeperClientLockPlugin : BaseUnityPlugin { internal const string PluginGuid = "empress.repo.shopkeeperclientlock"; internal const string PluginName = "Empress Shopkeeper Client Lock"; internal const string PluginVersion = "1.0.0"; private static ConfigEntry? _clientsCanPressShopkeeperButton; private static readonly Dictionary ReleaseCooldowns = new Dictionary(); private readonly Harmony _harmony = new Harmony("empress.repo.shopkeeperclientlock"); private void Awake() { _clientsCanPressShopkeeperButton = ((BaseUnityPlugin)this).Config.Bind("General", "ClientsCanPressShopkeeperButton", false, "Controls whether non-host clients can use the shopkeeper on/off switch in multiplayer."); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Empress Shopkeeper Client Lock 1.0.0 loaded."); } internal static bool ShouldBlockSwitchActivation(ShopKeeper shopKeeper) { if (!ShouldEnforceOnHost() || (Object)(object)shopKeeper == (Object)null) { return false; } GameObject onOffSwitch = shopKeeper.OnOffSwitch; if ((Object)(object)onOffSwitch == (Object)null) { return false; } if (!HasClientGrabber(FindSwitchPhysGrabObject(onOffSwitch))) { return HasClientGrabber(FindSwitchStaticGrabObject(onOffSwitch)); } return true; } internal static bool ShouldBlockPhysGrabStarted(PhysGrabObject physGrabObject, int playerPhotonID) { if (!ShouldBlockGrabStarted((Component)(object)physGrabObject, playerPhotonID, out PhysGrabber grabber)) { return false; } ReleaseClientGrabber(grabber, physGrabObject); return true; } internal static bool ShouldBlockStaticGrabStarted(StaticGrabObject staticGrabObject, int playerPhotonID) { if (!ShouldBlockGrabStarted((Component)(object)staticGrabObject, playerPhotonID, out PhysGrabber grabber)) { return false; } ReleaseClientGrabber(grabber, staticGrabObject); return true; } internal static void ReleaseClientSwitchGrabbers(ShopKeeper shopKeeper) { if (!ShouldEnforceOnHost() || (Object)(object)shopKeeper == (Object)null) { return; } GameObject onOffSwitch = shopKeeper.OnOffSwitch; if ((Object)(object)onOffSwitch == (Object)null) { return; } PhysGrabObject val = FindSwitchPhysGrabObject(onOffSwitch); if ((Object)(object)val != (Object)null) { foreach (PhysGrabber item in new List(val.playerGrabbing)) { if (IsNonHostGrabber(item)) { ReleaseClientGrabber(item, val); } } } StaticGrabObject val2 = FindSwitchStaticGrabObject(onOffSwitch); if (!((Object)(object)val2 != (Object)null)) { return; } foreach (PhysGrabber item2 in new List(val2.playerGrabbing)) { if (IsNonHostGrabber(item2)) { ReleaseClientGrabber(item2, val2); } } } private static bool ShouldBlockGrabStarted(Component grabObject, int playerPhotonID, out PhysGrabber? grabber) { grabber = null; if (!ShouldEnforceOnHost() || !IsShopkeeperSwitchGrabObject(grabObject)) { return false; } PhotonView val = PhotonView.Find(playerPhotonID); if (!Object.op_Implicit((Object)(object)val)) { return false; } grabber = ((Component)val).GetComponent(); return IsNonHostGrabber(grabber); } private static bool ShouldEnforceOnHost() { ConfigEntry? clientsCanPressShopkeeperButton = _clientsCanPressShopkeeperButton; if ((clientsCanPressShopkeeperButton == null || !clientsCanPressShopkeeperButton.Value) && SemiFunc.IsMultiplayer()) { return SemiFunc.IsMasterClient(); } return false; } private static bool HasClientGrabber(PhysGrabObject? physGrabObject) { if ((Object)(object)physGrabObject == (Object)null) { return false; } foreach (PhysGrabber item in physGrabObject.playerGrabbing) { if (IsNonHostGrabber(item)) { return true; } } return false; } private static bool HasClientGrabber(StaticGrabObject? staticGrabObject) { if ((Object)(object)staticGrabObject == (Object)null) { return false; } foreach (PhysGrabber item in staticGrabObject.playerGrabbing) { if (IsNonHostGrabber(item)) { return true; } } return false; } private static bool IsNonHostGrabber(PhysGrabber? grabber) { if ((Object)(object)grabber == (Object)null) { return false; } PlayerAvatar playerAvatar = grabber.playerAvatar; if ((Object)(object)playerAvatar == (Object)null || (Object)(object)playerAvatar.photonView == (Object)null) { return false; } return playerAvatar.photonView.Owner != PhotonNetwork.MasterClient; } private static bool IsShopkeeperSwitchGrabObject(Component grabObject) { if ((Object)(object)grabObject == (Object)null || (Object)(object)ShopKeeper.instance == (Object)null) { return false; } GameObject onOffSwitch = ShopKeeper.instance.OnOffSwitch; if ((Object)(object)onOffSwitch == (Object)null) { return false; } Transform transform = onOffSwitch.transform; Transform transform2 = grabObject.transform; if (!((Object)(object)transform == (Object)(object)transform2) && !transform.IsChildOf(transform2)) { return transform2.IsChildOf(transform); } return true; } private static PhysGrabObject? FindSwitchPhysGrabObject(GameObject switchObject) { if ((Object)(object)switchObject == (Object)null) { return null; } return switchObject.GetComponent() ?? switchObject.GetComponentInParent() ?? switchObject.GetComponentInChildren(true); } private static StaticGrabObject? FindSwitchStaticGrabObject(GameObject switchObject) { if ((Object)(object)switchObject == (Object)null) { return null; } return switchObject.GetComponent() ?? switchObject.GetComponentInParent() ?? switchObject.GetComponentInChildren(true); } private static void ReleaseClientGrabber(PhysGrabber? grabber, PhysGrabObject physGrabObject) { if (!((Object)(object)grabber == (Object)null) && !((Object)(object)physGrabObject == (Object)null)) { PhotonView component = ((Component)physGrabObject).GetComponent(); if (!((Object)(object)component == (Object)null) && TryBeginRelease(grabber)) { grabber.photonView.RPC("ReleaseObjectRPC", (RpcTarget)0, new object[3] { false, 0.5f, component.ViewID }); } } } private static void ReleaseClientGrabber(PhysGrabber? grabber, StaticGrabObject staticGrabObject) { if (!((Object)(object)grabber == (Object)null) && !((Object)(object)staticGrabObject == (Object)null)) { PhotonView component = ((Component)staticGrabObject).GetComponent(); if (!((Object)(object)component == (Object)null) && TryBeginRelease(grabber)) { grabber.photonView.RPC("ReleaseObjectRPC", (RpcTarget)0, new object[3] { true, 0.5f, component.ViewID }); } } } private static bool TryBeginRelease(PhysGrabber grabber) { if ((Object)(object)grabber.photonView == (Object)null) { return false; } int viewID = grabber.photonView.ViewID; float time = Time.time; if (ReleaseCooldowns.TryGetValue(viewID, out var value) && value > time) { return false; } ReleaseCooldowns[viewID] = time + 0.25f; return true; } } [HarmonyPatch(typeof(ShopKeeper), "WakeUpOrSleepLogic")] internal static class EmpressShopkeeperClientLockWakeUpOrSleepPatch { [HarmonyPrefix] private static bool EmpressPrefix(ShopKeeper __instance) { return !EmpressShopkeeperClientLockPlugin.ShouldBlockSwitchActivation(__instance); } } [HarmonyPatch(typeof(ShopKeeper), "Update")] internal static class EmpressShopkeeperClientLockShopKeeperUpdatePatch { [HarmonyPostfix] private static void EmpressPostfix(ShopKeeper __instance) { EmpressShopkeeperClientLockPlugin.ReleaseClientSwitchGrabbers(__instance); } } [HarmonyPatch(typeof(PhysGrabObject), "GrabStartedRPC")] internal static class EmpressShopkeeperClientLockPhysGrabStartedPatch { [HarmonyPrefix] private static bool EmpressPrefix(PhysGrabObject __instance, int playerPhotonID) { return !EmpressShopkeeperClientLockPlugin.ShouldBlockPhysGrabStarted(__instance, playerPhotonID); } } [HarmonyPatch(typeof(StaticGrabObject), "GrabStartedRPC")] internal static class EmpressShopkeeperClientLockStaticGrabStartedPatch { [HarmonyPrefix] private static bool EmpressPrefix(StaticGrabObject __instance, int playerPhotonID) { return !EmpressShopkeeperClientLockPlugin.ShouldBlockStaticGrabStarted(__instance, playerPhotonID); } } }