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 RerollHostOnly v4.0.0
RerollHostOnly.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; 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: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("REPOJP")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("zabuMod")] [assembly: AssemblyTitle("zabuMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace REPOJP.RerollHostOnly { [BepInPlugin("REPOJP.RerollHostOnly", "RerollHostOnly", "4.0.0")] public class RerollHostOnlyPlugin : BaseUnityPlugin { [HarmonyPatch] private static class UpgradeStandOnClickPatch { private static bool Prepare() { Type upgradeStandType = GetUpgradeStandType(); if (upgradeStandType != null) { return AccessTools.Method(upgradeStandType, "OnClick", (Type[])null, (Type[])null) != null; } return false; } private static MethodBase TargetMethod() { return AccessTools.Method(GetUpgradeStandType(), "OnClick", (Type[])null, (Type[])null); } private static bool Prefix(object __instance) { try { if (!IsEnabled()) { return true; } if (IsLocalAllowedToReroll()) { MarkStandAuthorized(__instance, 20f); return true; } if (ConfigBlockNonHostInteract != null && ConfigBlockNonHostInteract.Value) { if (ConfigShowBlockedMessage != null && ConfigShowBlockedMessage.Value && ConfigBlockedMessage != null) { SendPublicMessageWithCooldown(ConfigBlockedMessage.Value, "local_blocked", 1.5f); } return false; } return true; } catch (Exception ex) { LogFailure("UpgradeStand.OnClick", ex); return true; } } } [HarmonyPatch] private static class UpgradeStandStateSetPatch { private static bool Prepare() { Type upgradeStandType = GetUpgradeStandType(); if (upgradeStandType != null) { return AccessTools.Method(upgradeStandType, "StateSet", (Type[])null, (Type[])null) != null; } return false; } private static MethodBase TargetMethod() { return AccessTools.Method(GetUpgradeStandType(), "StateSet", (Type[])null, (Type[])null); } private static bool Prefix(object __instance, object[] __args) { try { if (!IsEnabled()) { return true; } if (__args == null || __args.Length == 0) { return true; } if (!StateArgumentIs(__args[0], "Press")) { return true; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return true; } if (IsStandAuthorized(__instance)) { return true; } if (StandHasHostGrabber(__instance)) { MarkStandAuthorized(__instance, 20f); return true; } if (StandHasOnlyNonHostGrabber(__instance)) { string message = ((ConfigBlockedMessage != null) ? ConfigBlockedMessage.Value : "Only the host can use the Upgrade Reroller."); SendPublicMessageWithCooldown(message, "state_blocked_" + GetStandKey(__instance), 1.5f); DebugLog("Blocked unauthorized UpgradeStand.State.Press."); return false; } return true; } catch (Exception ex) { LogFailure("UpgradeStand.StateSet", ex); return true; } } private static void Postfix(object __instance, object[] __args) { try { if (__args != null && __args.Length != 0 && (StateArgumentIs(__args[0], "Idle") || StateArgumentIs(__args[0], "Broken"))) { ClearStandAuthorization(__instance); } } catch { } } } [HarmonyPatch] private static class UpgradeStandHandleCostDisplayPatch { private static bool Prepare() { Type upgradeStandType = GetUpgradeStandType(); if (upgradeStandType != null) { return AccessTools.Method(upgradeStandType, "HandleCostDisplay", (Type[])null, (Type[])null) != null; } return false; } private static MethodBase TargetMethod() { return AccessTools.Method(GetUpgradeStandType(), "HandleCostDisplay", (Type[])null, (Type[])null); } private static void Postfix(object __instance) { try { if (IsEnabled() && ConfigShowHoverTextForNonHost != null && ConfigShowHoverTextForNonHost.Value && !IsLocalAllowedToReroll() && !StandStateIs(__instance, "Broken")) { object fieldValue = GetFieldValue(__instance, "buttonGrabObject"); if (fieldValue != null) { string value = ((ConfigNonHostHoverText != null) ? ConfigNonHostHoverText.Value : "HOST ONLY REROLL"); SetFieldValue(fieldValue, "hoverText", value); } } } catch (Exception ex) { LogFailure("UpgradeStand.HandleCostDisplay", ex); } } } [HarmonyPatch] private static class StaticGrabObjectGrabStartedRpcPatch { private static bool Prepare() { Type type = AccessTools.TypeByName("StaticGrabObject"); if (type != null) { return AccessTools.Method(type, "GrabStartedRPC", (Type[])null, (Type[])null) != null; } return false; } private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("StaticGrabObject"); return AccessTools.Method(type, "GrabStartedRPC", (Type[])null, (Type[])null); } private static bool Prefix(object __instance, int playerPhotonID) { try { if (!IsEnabled()) { return true; } if (!TryGetUpgradeStandFromStaticGrabObject(__instance, out var stand)) { return true; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return true; } return HandleNonHostGrabAttempt(stand, playerPhotonID); } catch (Exception ex) { LogFailure("StaticGrabObject.GrabStartedRPC", ex); return true; } } } public const string PluginGuid = "REPOJP.RerollHostOnly"; public const string PluginName = "RerollHostOnly"; public const string PluginVersion = "4.0.0"; private static ManualLogSource Log; private static Harmony harmony; private static ConfigEntry<bool> ConfigEnable; private static ConfigEntry<bool> ConfigShowDebugLog; private static ConfigEntry<bool> ConfigHostOnlyReroll; private static ConfigEntry<bool> ConfigAllowSinglePlayer; private static ConfigEntry<bool> ConfigBlockNonHostInteract; private static ConfigEntry<bool> ConfigShowBlockedMessage; private static ConfigEntry<string> ConfigBlockedMessage; private static ConfigEntry<bool> ConfigShowHoverTextForNonHost; private static ConfigEntry<string> ConfigNonHostHoverText; private static Type upgradeStandType; private static Type upgradeStandStateType; private static Type physGrabberType; private static Type playerAvatarType; private static readonly Dictionary<int, float> AuthorizedStandUntil = new Dictionary<int, float>(); private static readonly Dictionary<string, float> MessageCooldownUntil = new Dictionary<string, float>(); private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown try { ((Component)this).transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); Log = ((BaseUnityPlugin)this).Logger; BindConfig(); CacheTypes(); harmony = new Harmony("REPOJP.RerollHostOnly"); harmony.PatchAll(typeof(RerollHostOnlyPlugin).Assembly); Log.LogInfo((object)"RerollHostOnly loaded. Version 4.0.0"); } catch (Exception ex) { if (((BaseUnityPlugin)this).Logger != null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Awake\n" + ex)); } } } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } } catch (Exception ex) { if (Log != null) { Log.LogError((object)("Failure: OnDestroy\n" + ex)); } } } private void BindConfig() { ConfigEnable = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable", true, "Enable this mod.このMODの有効化"); ConfigShowDebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowDebugLog", false, "Show debug logs.デバッグログの表示"); ConfigHostOnlyReroll = ((BaseUnityPlugin)this).Config.Bind<bool>("Permission", "HostOnlyReroll", true, "Allow only the host to start the Upgrade Reroller.Upgrade Rerollerの開始をホストのみに制限"); ConfigAllowSinglePlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("Permission", "AllowSinglePlayer", true, "Allow normal rerolling in single player.シングルプレイでの通常使用許可"); ConfigBlockNonHostInteract = ((BaseUnityPlugin)this).Config.Bind<bool>("Permission", "BlockNonHostInteract", true, "Block non-host interactions before reroll starts.非ホスト操作の開始前ブロック"); ConfigShowBlockedMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("Message", "ShowBlockedMessage", true, "Show a message when a non-host tries to use the reroller.非ホスト操作時メッセージの表示"); ConfigBlockedMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Message", "BlockedMessage", "Only the host can use the Upgrade Reroller.", "Blocked message text.ブロック時メッセージ"); ConfigShowHoverTextForNonHost = ((BaseUnityPlugin)this).Config.Bind<bool>("Message", "ShowHoverTextForNonHost", true, "Show host-only hover text for non-host clients that also have this mod.このMODを導入した非ホスト向けHover表示"); ConfigNonHostHoverText = ((BaseUnityPlugin)this).Config.Bind<string>("Message", "NonHostHoverText", "HOST ONLY REROLL", "Non-host hover text.非ホスト向けHover表示"); } private static void CacheTypes() { upgradeStandType = AccessTools.TypeByName("UpgradeStand"); physGrabberType = AccessTools.TypeByName("PhysGrabber"); playerAvatarType = AccessTools.TypeByName("PlayerAvatar"); if (upgradeStandType != null) { upgradeStandStateType = AccessTools.Inner(upgradeStandType, "State"); } } private static Type GetUpgradeStandType() { if (upgradeStandType == null) { upgradeStandType = AccessTools.TypeByName("UpgradeStand"); } return upgradeStandType; } private static Type GetUpgradeStandStateType() { if (upgradeStandStateType == null && GetUpgradeStandType() != null) { upgradeStandStateType = AccessTools.Inner(upgradeStandType, "State"); } return upgradeStandStateType; } private static Type GetPhysGrabberType() { if (physGrabberType == null) { physGrabberType = AccessTools.TypeByName("PhysGrabber"); } return physGrabberType; } private static bool IsEnabled() { if (ConfigEnable != null && ConfigEnable.Value && ConfigHostOnlyReroll != null) { return ConfigHostOnlyReroll.Value; } return false; } private static bool IsLocalAllowedToReroll() { try { if (!SemiFunc.IsMultiplayer()) { return ConfigAllowSinglePlayer == null || ConfigAllowSinglePlayer.Value; } return SemiFunc.IsMasterClientOrSingleplayer(); } catch { return false; } } private static object GetStandState(string stateName) { try { Type type = GetUpgradeStandStateType(); if (type == null) { return null; } return Enum.Parse(type, stateName); } catch { return null; } } private static string GetStateName(object state) { try { if (state == null) { return string.Empty; } if (state.GetType().IsEnum) { return Enum.GetName(state.GetType(), state); } return Convert.ToInt32(state) switch { 0 => "Idle", 1 => "Press", 2 => "PressFail", 3 => "PressSucceed", 4 => "Charging", 5 => "ChargingRollback", 6 => "RerollCloseHatch", 7 => "RerollRollStart", 8 => "RerollRolling", 9 => "RerollRollEnd", 10 => "RerollOpenHatch", 11 => "Broken", _ => string.Empty, }; } catch { return string.Empty; } } private static bool StateArgumentIs(object state, string stateName) { return string.Equals(GetStateName(state), stateName, StringComparison.Ordinal); } private static bool StandStateIs(object stand, string stateName) { try { if (stand == null) { return false; } object standState = GetStandState(stateName); if (standState != null) { MethodInfo methodInfo = AccessTools.Method(GetUpgradeStandType(), "StateIs", (Type[])null, (Type[])null); if (methodInfo != null && methodInfo.Invoke(stand, new object[1] { standState }) is bool result) { return result; } } object fieldValue = GetFieldValue(stand, "currentState"); return string.Equals(GetStateName(fieldValue), stateName, StringComparison.Ordinal); } catch { return false; } } private static object GetFieldValue(object instance, string fieldName) { try { if (instance == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); if (fieldInfo == null) { return null; } return fieldInfo.GetValue(instance); } catch { return null; } } private static void SetFieldValue(object instance, string fieldName, object value) { try { if (instance != null) { FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); if (!(fieldInfo == null)) { fieldInfo.SetValue(instance, value); } } } catch (Exception ex) { LogFailure("SetFieldValue", ex); } } private static bool TryGetUpgradeStandFromStaticGrabObject(object staticGrabObject, out object stand) { stand = null; try { if (staticGrabObject == null) { return false; } Type type = GetUpgradeStandType(); if (type == null) { return false; } Component val = (Component)((staticGrabObject is Component) ? staticGrabObject : null); if ((Object)(object)val == (Object)null) { return false; } stand = val.GetComponentInParent(type); if (stand == null) { return false; } object fieldValue = GetFieldValue(stand, "buttonGrabObject"); if (fieldValue == null) { return false; } return fieldValue == staticGrabObject; } catch { stand = null; return false; } } private static int GetStandKey(object stand) { try { if (stand == null) { return 0; } Component val = (Component)((stand is Component) ? stand : null); if ((Object)(object)val != (Object)null) { PhotonView component = val.GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.ViewID != 0) { return component.ViewID; } return ((Object)val).GetInstanceID(); } return stand.GetHashCode(); } catch { return 0; } } private static void MarkStandAuthorized(object stand, float seconds) { try { int standKey = GetStandKey(stand); if (standKey != 0) { AuthorizedStandUntil[standKey] = Time.time + Mathf.Max(1f, seconds); } } catch (Exception ex) { LogFailure("MarkStandAuthorized", ex); } } private static bool IsStandAuthorized(object stand) { try { int standKey = GetStandKey(stand); if (standKey == 0) { return false; } if (!AuthorizedStandUntil.TryGetValue(standKey, out var value)) { return false; } if (Time.time <= value) { return true; } AuthorizedStandUntil.Remove(standKey); return false; } catch { return false; } } private static void ClearStandAuthorization(object stand) { try { int standKey = GetStandKey(stand); if (standKey != 0 && AuthorizedStandUntil.ContainsKey(standKey)) { AuthorizedStandUntil.Remove(standKey); } } catch { } } private static bool IsGrabberHost(object grabber) { try { if (!SemiFunc.IsMultiplayer()) { return true; } if (grabber == null) { return false; } object fieldValue = GetFieldValue(grabber, "photonView"); PhotonView val = (PhotonView)((fieldValue is PhotonView) ? fieldValue : null); if ((Object)(object)val == (Object)null) { Component val2 = (Component)((grabber is Component) ? grabber : null); if ((Object)(object)val2 != (Object)null) { val = val2.GetComponent<PhotonView>(); } } if ((Object)(object)val == (Object)null || val.Owner == null) { return false; } return val.Owner.IsMasterClient; } catch { return false; } } private static bool IsPlayerPhotonIdHost(int playerPhotonId) { try { PhotonView val = PhotonView.Find(playerPhotonId); if ((Object)(object)val == (Object)null) { return false; } Type type = GetPhysGrabberType(); object obj = null; if (type != null) { obj = ((Component)val).GetComponent(type); } if (obj == null) { obj = val; } return IsGrabberHost(obj); } catch { return false; } } private static bool StandHasHostGrabber(object stand) { try { object fieldValue = GetFieldValue(stand, "buttonGrabObject"); if (!(GetFieldValue(fieldValue, "playerGrabbing") is IList list)) { return false; } for (int i = 0; i < list.Count; i++) { object grabber = list[i]; if (IsGrabberHost(grabber)) { return true; } } } catch { } return false; } private static bool StandHasOnlyNonHostGrabber(object stand) { try { object fieldValue = GetFieldValue(stand, "buttonGrabObject"); if (!(GetFieldValue(fieldValue, "playerGrabbing") is IList list)) { return false; } bool result = false; for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj != null) { result = true; if (IsGrabberHost(obj)) { return false; } } } return result; } catch { return false; } } private static bool HandleNonHostGrabAttempt(object stand, int playerPhotonId) { try { if (!IsEnabled()) { return true; } if (ConfigBlockNonHostInteract != null && !ConfigBlockNonHostInteract.Value) { return true; } if (IsPlayerPhotonIdHost(playerPhotonId)) { MarkStandAuthorized(stand, 20f); return true; } SendBlockedMessage(playerPhotonId); return false; } catch (Exception ex) { LogFailure("HandleNonHostGrabAttempt", ex); return false; } } private static void SendBlockedMessage(int playerPhotonId) { try { if (ConfigShowBlockedMessage != null && ConfigShowBlockedMessage.Value) { string message = ((ConfigBlockedMessage != null) ? ConfigBlockedMessage.Value : "Only the host can use the Upgrade Reroller."); string key = "blocked_" + playerPhotonId; SendPublicMessageWithCooldown(message, key, 1.5f); } } catch { } } private static void SendPublicMessageWithCooldown(string message, string key, float cooldownSeconds) { try { if (!string.IsNullOrEmpty(message) && (!MessageCooldownUntil.TryGetValue(key, out var value) || !(Time.time < value))) { MessageCooldownUntil[key] = Time.time + Mathf.Max(0.1f, cooldownSeconds); if ((!SemiFunc.IsMasterClientOrSingleplayer() || !TrySendChatMessage(message)) && Log != null) { Log.LogInfo((object)message); } } } catch (Exception ex) { LogFailure("SendPublicMessage", ex); } } private static bool TrySendChatMessage(string message) { try { if (playerAvatarType == null) { playerAvatarType = AccessTools.TypeByName("PlayerAvatar"); } if (playerAvatarType == null) { return false; } FieldInfo fieldInfo = AccessTools.Field(playerAvatarType, "instance"); if (fieldInfo == null) { return false; } object value = fieldInfo.GetValue(null); if (value == null) { return false; } MethodInfo methodInfo = AccessTools.Method(playerAvatarType, "ChatMessageSend", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo == null) { return false; } methodInfo.Invoke(value, new object[1] { message }); return true; } catch { return false; } } private static void DebugLog(string message) { try { if (ConfigShowDebugLog != null && ConfigShowDebugLog.Value && Log != null) { Log.LogInfo((object)message); } } catch { } } private static void LogFailure(string name, Exception ex) { try { if (Log != null) { Log.LogError((object)("Failure: " + name + "\n" + ex)); } } catch { } } } }