using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ShopGuardian")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShopGuardian")]
[assembly: AssemblyTitle("ShopGuardian")]
[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 ShopGuardian
{
[BepInPlugin("pl.kuba.shopguardian", "Shop Guardian", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class ShopGuardianPlugin : BaseUnityPlugin
{
public const string PluginGuid = "pl.kuba.shopguardian";
public const string PluginName = "Shop Guardian";
public const string PluginVersion = "1.0.1";
private Harmony _harmony;
internal static ManualLogSource LogS;
private ConfigEntry<bool> _blockArcadia;
private ConfigEntry<bool> _blockAllThirdParty;
private ConfigEntry<bool> _forceDisableRandomSelection;
private ConfigEntry<bool> _writeArcadiaCfg;
private static ShopGuardianPlugin _instance;
internal static ShopGuardianPlugin Instance => _instance;
private void Awake()
{
_instance = this;
LogS = ((BaseUnityPlugin)this).Logger;
_blockArcadia = ((BaseUnityPlugin)this).Config.Bind<bool>("Blockers", "BlockArcadiaBetterShop", true, "Block shop registrations coming specifically from ArcadiaBetterShop/KagomesMod.");
_blockAllThirdParty = ((BaseUnityPlugin)this).Config.Bind<bool>("Blockers", "BlockAllThirdPartyShopOverrides", false, "Block ANY third-party shop registrations (allows only vanilla/REPOShopLib internal).");
_forceDisableRandomSelection = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "DisableRandomShopSelection", true, "Force-disable random/alt shop selection in REPOShopLib, when possible.");
_writeArcadiaCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "WriteArcadiaBetterShopConfigOverride", true, "On startup, write/update ArcadiaBetterShop config to disable its shop features.");
((BaseUnityPlugin)this).Logger.LogInfo((object)"[Shop Guardian] Booting…");
TryWriteArcadiaConfig();
TryForceREPOShopLibFlags();
TryPatchREPOShopLib();
}
private void TryWriteArcadiaConfig()
{
if (!_writeArcadiaCfg.Value)
{
return;
}
try
{
string text = Path.Combine(Paths.ConfigPath, "ArcadiaBetterShop.arcadiabettershop.cfg");
string[] array = new string[6] { "# Auto-generated by Shop Guardian to keep the vanilla shop intact.", "# You can set WriteArcadiaBetterShopConfigOverride=false in pl.kuba.shopguardian.cfg to stop this.", "", "[Shop]", "UseRandomShop = false", "EnableRandomShopSelection = false" };
if (!File.Exists(text))
{
File.WriteAllLines(text, array);
((BaseUnityPlugin)this).Logger.LogInfo((object)("Wrote " + text));
return;
}
string text2 = File.ReadAllText(text);
if (!text2.Contains("UseRandomShop") || !text2.Contains("EnableRandomShopSelection"))
{
File.AppendAllText(text, Environment.NewLine + string.Join(Environment.NewLine, array.Skip(3)));
((BaseUnityPlugin)this).Logger.LogInfo((object)("Updated " + text + " with missing keys."));
return;
}
text2 = Regex.Replace(text2, "UseRandomShop\\s*=\\s*\\w+", "UseRandomShop = false");
text2 = Regex.Replace(text2, "EnableRandomShopSelection\\s*=\\s*\\w+", "EnableRandomShopSelection = false");
File.WriteAllText(text, text2);
((BaseUnityPlugin)this).Logger.LogInfo((object)("Ensured disabling flags in " + text + "."));
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Arcadia config override failed: " + ex.Message));
}
}
private void TryForceREPOShopLibFlags()
{
if (!_forceDisableRandomSelection.Value)
{
return;
}
try
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name.Contains("REPOShopLib"));
if (assembly == null)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"REPOShopLib not loaded yet; skipping flag force.");
return;
}
Type type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == "ShopUtils");
if (type == null)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"REPOShopLib.ShopUtils not found; skipping flag force.");
return;
}
string[] array = new string[2] { "EnableRandomShopSelection", "UseRandomShop" };
foreach (string text in array)
{
PropertyInfo property = type.GetProperty(text, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null && property.CanWrite)
{
try
{
property.SetValue(null, false);
((BaseUnityPlugin)this).Logger.LogInfo((object)("Set REPOShopLib.ShopUtils." + text + " = false"));
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to set ShopUtils." + text + ": " + ex.Message));
}
}
}
}
catch (Exception ex2)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Error while forcing REPOShopLib flags: " + ex2.Message));
}
}
private void TryPatchREPOShopLib()
{
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Expected O, but got Unknown
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Expected O, but got Unknown
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Expected O, but got Unknown
try
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name.Contains("REPOShopLib"));
if (assembly == null)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"REPOShopLib not loaded; will rely on config override.");
return;
}
Type type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == "ShopUtils");
if (type == null)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"REPOShopLib.ShopUtils not found; cannot patch.");
return;
}
_harmony = new Harmony("pl.kuba.shopguardian");
string[] array = new string[2] { "RegisterNamedShop", "RegisterShopRoom" };
foreach (string text in array)
{
MethodInfo methodInfo = AccessTools.Method(type, text, (Type[])null, (Type[])null);
if (methodInfo != null)
{
HarmonyMethod val = new HarmonyMethod(typeof(ShopGuardianPlugin).GetMethod("GenericShopGatePrefix", BindingFlags.Static | BindingFlags.NonPublic));
_harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched ShopUtils." + text));
}
}
MethodInfo methodInfo2 = AccessTools.Method(type, "EnableRandomShopSelection", (Type[])null, (Type[])null);
if (methodInfo2 != null)
{
HarmonyMethod val2 = new HarmonyMethod(typeof(ShopGuardianPlugin).GetMethod("ForceDisableRandomSelectionPrefix", BindingFlags.Static | BindingFlags.NonPublic));
_harmony.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched ShopUtils.EnableRandomShopSelection");
}
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Harmony patching failed: " + ex.Message));
}
}
private static bool GenericShopGatePrefix(MethodBase __originalMethod)
{
try
{
if ((Object)(object)Instance != (Object)null && Instance._blockAllThirdParty.Value)
{
LogS.LogDebug((object)("Blocked " + __originalMethod?.Name + " (all third-party)."));
return false;
}
if ((Object)(object)Instance != (Object)null && Instance._blockArcadia.Value && IsCallFromAssemblyMatching("ArcadiaBetterShop", "KagomesMod"))
{
LogS.LogInfo((object)("Blocked " + __originalMethod?.Name + " from ArcadiaBetterShop/KagomesMod."));
return false;
}
}
catch (Exception ex)
{
LogS.LogWarning((object)("GenericShopGatePrefix error: " + ex.Message));
}
return true;
}
private static bool ForceDisableRandomSelectionPrefix()
{
try
{
if ((Object)(object)Instance != (Object)null && Instance._forceDisableRandomSelection.Value)
{
LogS.LogInfo((object)"Prevented enabling random shop selection.");
return false;
}
}
catch (Exception ex)
{
LogS.LogWarning((object)("ForceDisableRandomSelectionPrefix error: " + ex.Message));
}
return true;
}
private static bool IsCallFromAssemblyMatching(params string[] substrings)
{
StackFrame[] frames = new StackTrace(2, fNeedFileInfo: false).GetFrames();
foreach (StackFrame obj in frames)
{
Type type = obj.GetMethod()?.DeclaringType;
if (!(type == null))
{
string asmName = type.Assembly.GetName().Name;
if (!asmName.Contains("ShopGuardian") && !asmName.Contains("REPOShopLib") && substrings.Any((string s) => asmName.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))
{
return true;
}
}
}
return false;
}
}
}