using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Mirror; using QuickBoxRecycle.Configuration; using QuickBoxRecycle.Features; using QuickBoxRecycle.Localization; using TMPro; using UnityEngine; using UnityEngine.EventSystems; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("QuickBoxRecycle")] [assembly: AssemblyDescription("Quick Box Recycle mod for Supermarket Together by Ice Box Studio")] [assembly: AssemblyCompany("Ice Box Studio")] [assembly: AssemblyProduct("QuickBoxRecycle")] [assembly: AssemblyCopyright("Copyright © 2026 Ice Box Studio All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("9ac2c2e4-0d2a-42f8-95ef-f3ebbb7e9cf8")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace QuickBoxRecycle { public static class PluginInfo { public const string PLUGIN_GUID = "IceBoxStudio.SupermarketTogether.QuickBoxRecycle"; public const string PLUGIN_NAME = "QuickBoxRecycle"; public const string PLUGIN_VERSION = "1.0.0"; } [BepInPlugin("IceBoxStudio.SupermarketTogether.QuickBoxRecycle", "QuickBoxRecycle", "1.0.0")] public class QuickBoxRecycle : BaseUnityPlugin { public static QuickBoxRecycle _Instance; private Harmony _harmony; private bool patchesApplied; public static QuickBoxRecycle Instance => _Instance; internal static ManualLogSource Logger { get; private set; } private void Awake() { _Instance = this; Logger = ((BaseUnityPlugin)this).Logger; try { Logger.LogInfo((object)"============================================="); Logger.LogInfo((object)("QuickBoxRecycle " + ModLocalizationManager.Instance.GetLocalizedText("plugin.initializing"))); Logger.LogInfo((object)(ModLocalizationManager.Instance.GetLocalizedText("plugin.author_prefix") + "Ice Box Studio(https://steamcommunity.com/id/ibox666/)")); ConfigManager.Initialize(((BaseUnityPlugin)this).Config); ApplyPatches(); Logger.LogInfo((object)("QuickBoxRecycle " + ModLocalizationManager.Instance.GetLocalizedText("plugin.initialized"))); Logger.LogInfo((object)"============================================="); } catch (Exception ex) { Logger.LogError((object)("QuickBoxRecycle 初始化错误: " + ex.Message + "\n" + ex.StackTrace)); } } private void Update() { QuickRecycleController.Tick(); } private void ApplyPatches() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if (!patchesApplied) { try { _harmony = new Harmony("IceBoxStudio.SupermarketTogether.QuickBoxRecycle"); _harmony.PatchAll(); patchesApplied = true; return; } catch (Exception ex) { Logger.LogError((object)("QuickBoxRecycle 应用补丁错误: " + ex.Message + "\n" + ex.StackTrace)); return; } } Logger.LogInfo((object)ModLocalizationManager.Instance.GetLocalizedText("plugin.patches_skipped")); } } } namespace QuickBoxRecycle.Localization { public static class LocalizationHelper { public static Dictionary GetDefaultTranslations(string language) { Dictionary dictionary = new Dictionary(); switch (language) { case "Localization_CH1": dictionary.Add("plugin.initializing", "开始初始化..."); dictionary.Add("plugin.author_prefix", "作者:"); dictionary.Add("plugin.initialized", "初始化成功!"); dictionary.Add("plugin.patches_skipped", "补丁已应用,跳过..."); dictionary.Add("config.recycle_shortcut", "一键回收空箱的快捷键"); dictionary.Add("config.show_notifications", "显示回收提示"); dictionary.Add("recycle.success", "已快速回收空箱,获得 {0}"); dictionary.Add("recycle.no_box", "当前没有抱着可回收的普通箱子。"); dictionary.Add("recycle.not_empty", "当前箱子不是空箱,无法快速回收。"); break; case "Localization_CH2": dictionary.Add("plugin.initializing", "開始初始化..."); dictionary.Add("plugin.author_prefix", "作者:"); dictionary.Add("plugin.initialized", "初始化成功!"); dictionary.Add("plugin.patches_skipped", "補丁已套用,跳過..."); dictionary.Add("config.recycle_shortcut", "一鍵回收空箱的快捷鍵"); dictionary.Add("config.show_notifications", "顯示回收提示"); dictionary.Add("recycle.success", "已快速回收空箱,獲得 {0}"); dictionary.Add("recycle.no_box", "目前沒有抱著可回收的普通箱子。"); dictionary.Add("recycle.not_empty", "目前箱子不是空箱,無法快速回收。"); break; default: dictionary.Add("plugin.initializing", "Initializing..."); dictionary.Add("plugin.author_prefix", "Author: "); dictionary.Add("plugin.initialized", "Initialized successfully!"); dictionary.Add("plugin.patches_skipped", "Patches already applied, skipping..."); dictionary.Add("config.recycle_shortcut", "Hotkey for quick empty box recycling"); dictionary.Add("config.show_notifications", "Show recycle notifications"); dictionary.Add("recycle.success", "Empty box recycled, earned {0}"); dictionary.Add("recycle.no_box", "You are not holding a recyclable regular box."); dictionary.Add("recycle.not_empty", "The current box is not empty and cannot be recycled."); break; case "Localization_JP": dictionary.Add("plugin.initializing", "初期化中..."); dictionary.Add("plugin.author_prefix", "作者:"); dictionary.Add("plugin.initialized", "初期化に成功しました!"); dictionary.Add("plugin.patches_skipped", "パッチは既に適用されているため、スキップします..."); dictionary.Add("config.recycle_shortcut", "空箱を即時回収するホットキー"); dictionary.Add("config.show_notifications", "回収通知を表示"); dictionary.Add("recycle.success", "空箱を即時回収し、{0} を獲得しました"); dictionary.Add("recycle.no_box", "回収可能な通常の箱を持っていません。"); dictionary.Add("recycle.not_empty", "現在の箱は空ではないため、即時回収できません。"); break; } return dictionary; } } public class ModLocalizationManager { private const string ChineseSimplifiedLocale = "Localization_CH1"; private const string ChineseTraditionalLocale = "Localization_CH2"; private const string EnglishLocale = "Localization_EN"; private const string JapaneseLocale = "Localization_JP"; private static ModLocalizationManager _instance; private readonly Dictionary> _localizations = new Dictionary>(); private string _currentLocale = "Localization_CH1"; public static readonly string[] SupportedLanguages = new string[4] { "Localization_CH1", "Localization_CH2", "Localization_EN", "Localization_JP" }; public static ModLocalizationManager Instance => _instance ?? (_instance = new ModLocalizationManager()); private ModLocalizationManager() { Initialize(); } public void Initialize() { string[] supportedLanguages = SupportedLanguages; foreach (string text in supportedLanguages) { Dictionary defaultTranslations = LocalizationHelper.GetDefaultTranslations(text); if (defaultTranslations != null && defaultTranslations.Count != 0) { _localizations[text] = defaultTranslations; } } RefreshCurrentLocale(); } public string GetLocalizedText(string key, params object[] args) { RefreshCurrentLocale(); string text = ResolveCurrentLocale(); if (TryGetLocalizedText(text, key, out var text2) || (text != "Localization_EN" && TryGetLocalizedText("Localization_EN", key, out text2))) { return FormatLocalizedText(text2, args); } return key; } private string ResolveCurrentLocale() { if (string.IsNullOrEmpty(_currentLocale) || !_localizations.ContainsKey(_currentLocale)) { _currentLocale = "Localization_EN"; } return _currentLocale; } private bool TryGetLocalizedText(string locale, string key, out string text) { text = null; if (!string.IsNullOrEmpty(locale) && _localizations.TryGetValue(locale, out var value)) { return value.TryGetValue(key, out text); } return false; } private static string FormatLocalizedText(string text, object[] args) { if (args == null || args.Length == 0) { return text; } return string.Format(text, args); } private void RefreshCurrentLocale() { string currentGameLocale = GetCurrentGameLocale(); if (!string.IsNullOrEmpty(currentGameLocale)) { _currentLocale = MapGameLocaleToModLocale(currentGameLocale); } } private string GetCurrentGameLocale() { string text = Application.persistentDataPath + "/Settings/GameOptions.es3"; if (!ES3.KeyExists("GameLanguage", text)) { return null; } return ES3.Load("GameLanguage", text); } private static string MapGameLocaleToModLocale(string gameLocale) { switch (gameLocale) { case "Localization_CH1": case "Localization_CH2": case "Localization_JP": case "Localization_EN": return gameLocale; default: return "Localization_EN"; } } } } namespace QuickBoxRecycle.Features { internal static class QuickRecycleController { private const float BoxReward = 1.5f; private const float Cooldown = 0.25f; private static float _nextRecycleTime; public static void Tick() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (ConfigManager.Instance != null && Input.GetKeyDown(ConfigManager.Instance.RecycleShortcut.Value) && !IsUiBlocked()) { TryRecycle(); } } private static void TryRecycle() { if (Time.unscaledTime < _nextRecycleTime) { return; } PlayerNetwork localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { return; } if (!HasBox(localPlayer)) { Notify("recycle.no_box"); return; } if (!IsEmptyBox(localPlayer)) { Notify("recycle.not_empty"); return; } GameData instance = GameData.Instance; UpgradesManager val = (((Object)(object)instance != (Object)null) ? ((Component)instance).GetComponent() : null); if (!((Object)(object)instance == (Object)null) && !((Object)(object)val == (Object)null)) { float num = Mathf.Round(1.5f * (float)val.boxRecycleFactor * 100f) / 100f; localPlayer.CmdChangeEquippedItem(0); instance.CmdAlterFunds(num); if ((Object)(object)AchievementsManager.Instance != (Object)null) { AchievementsManager.Instance.CmdAddAchievementPoint(2, 1); } if ((Object)(object)StatisticsManager.Instance != (Object)null && NetworkServer.active) { StatisticsManager.Instance.AddDataFromFSMOrScript(0, 1); } _nextRecycleTime = Time.unscaledTime + 0.25f; string text = (((Object)(object)ProductListing.Instance != (Object)null) ? ProductListing.Instance.ConvertFloatToTextPrice(num) : ("$" + num.ToString("0.00"))); Notify("recycle.success", text); } } private static PlayerNetwork GetLocalPlayer() { PlayerNetwork[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && ((NetworkBehaviour)array[i]).isLocalPlayer) { return array[i]; } } return null; } private static bool HasBox(PlayerNetwork player) { if (player.equippedItem == 1) { return player.extraParameter1 >= 0; } return false; } private static bool IsEmptyBox(PlayerNetwork player) { return player.extraParameter2 <= 0; } private static bool IsUiBlocked() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 if ((Object)(object)EventSystem.current != (Object)null && (Object)(object)EventSystem.current.currentSelectedGameObject != (Object)null) { return true; } if (Cursor.visible || (int)Cursor.lockState != 1) { return true; } if ((Object)(object)GameCanvas.Instance == (Object)null) { return false; } if (!IsPanelOpen("Builder") && !IsPanelOpen("SurveillanceContainer") && !IsPanelOpen("EndDayStats") && !IsPanelOpen("SavingContainer")) { return IsPanelOpen("HostDisconnect"); } return true; } private static bool IsPanelOpen(string path) { Transform val = ((Component)GameCanvas.Instance).transform.Find(path); if ((Object)(object)val != (Object)null) { return ((Component)val).gameObject.activeInHierarchy; } return false; } private static void Notify(string localizationKey, params object[] args) { if (ConfigManager.Instance != null && ConfigManager.Instance.ShowNotifications.Value) { ShowNotice(ModLocalizationManager.Instance.GetLocalizedText(localizationKey, args)); } } private static void ShowNotice(string message) { if (!((Object)(object)GameCanvas.Instance == (Object)null) && !((Object)(object)GameCanvas.Instance.notificationPrefab == (Object)null) && !((Object)(object)GameCanvas.Instance.notificationParentTransform == (Object)null)) { GameObject obj = Object.Instantiate(GameCanvas.Instance.notificationPrefab, GameCanvas.Instance.notificationParentTransform); TextMeshProUGUI component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { ((TMP_Text)component).text = message; } obj.SetActive(true); } } } } namespace QuickBoxRecycle.Configuration { public class ConfigManager { private static ConfigManager _instance; private readonly ConfigFile _configFile; private readonly Dictionary> _boolConfigs = new Dictionary>(); private readonly Dictionary> _stringConfigs = new Dictionary>(); private readonly Dictionary> _intConfigs = new Dictionary>(); private readonly Dictionary> _floatConfigs = new Dictionary>(); private readonly Dictionary> _keyCodeConfigs = new Dictionary>(); public static ConfigManager Instance => _instance; public ConfigEntry RecycleShortcut { get; private set; } public ConfigEntry ShowNotifications { get; private set; } private ConfigManager(ConfigFile configFile) { _configFile = configFile; InitializeDefaultConfigs(); } public static void Initialize(ConfigFile configFile) { if (_instance == null) { _instance = new ConfigManager(configFile); } } private void InitializeDefaultConfigs() { RecycleShortcut = RegisterKeyCode("QuickRecycle", "RecycleShortcut", GetLocalizedDescription("config.recycle_shortcut"), (KeyCode)120); ShowNotifications = RegisterBool("QuickRecycle", "ShowNotifications", GetLocalizedDescription("config.show_notifications"), defaultValue: true); } private string GetLocalizedDescription(string key) { return ModLocalizationManager.Instance?.GetLocalizedText(key) ?? key; } public ConfigEntry RegisterBool(string section, string key, string description, bool defaultValue) { ConfigEntry val = _configFile.Bind(section, key, defaultValue, description); _boolConfigs[key] = val; return val; } public ConfigEntry RegisterString(string section, string key, string description, string defaultValue) { ConfigEntry val = _configFile.Bind(section, key, defaultValue, description); _stringConfigs[key] = val; return val; } public ConfigEntry RegisterKeyCode(string section, string key, string description, KeyCode defaultValue) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) ConfigEntry val = _configFile.Bind(section, key, defaultValue, description); _keyCodeConfigs[key] = val; return val; } public ConfigEntry RegisterInt(string section, string key, string description, int defaultValue) { ConfigEntry val = _configFile.Bind(section, key, defaultValue, description); _intConfigs[key] = val; return val; } public ConfigEntry RegisterIntRange(string section, string key, string description, int defaultValue, int minValue, int maxValue) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown ConfigEntry val = _configFile.Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(minValue, maxValue), Array.Empty())); _intConfigs[key] = val; return val; } public ConfigEntry RegisterFloat(string section, string key, string description, float defaultValue) { ConfigEntry val = _configFile.Bind(section, key, defaultValue, description); _floatConfigs[key] = val; return val; } public ConfigEntry RegisterFloatRange(string section, string key, string description, float defaultValue, float minValue, float maxValue) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown ConfigEntry val = _configFile.Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(minValue, maxValue), Array.Empty())); _floatConfigs[key] = val; return val; } } }