Decompiled source of QuickBoxRecycle v1.0.0

BepInEx/plugins/QuickBoxRecycle.dll

Decompiled 2 months ago
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<string, string> GetDefaultTranslations(string language)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			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<string, Dictionary<string, string>> _localizations = new Dictionary<string, Dictionary<string, string>>();

		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<string, string> 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<string>("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<UpgradesManager>() : 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<PlayerNetwork>((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<GameObject>(GameCanvas.Instance.notificationPrefab, GameCanvas.Instance.notificationParentTransform);
				TextMeshProUGUI component = obj.GetComponent<TextMeshProUGUI>();
				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<string, ConfigEntry<bool>> _boolConfigs = new Dictionary<string, ConfigEntry<bool>>();

		private readonly Dictionary<string, ConfigEntry<string>> _stringConfigs = new Dictionary<string, ConfigEntry<string>>();

		private readonly Dictionary<string, ConfigEntry<int>> _intConfigs = new Dictionary<string, ConfigEntry<int>>();

		private readonly Dictionary<string, ConfigEntry<float>> _floatConfigs = new Dictionary<string, ConfigEntry<float>>();

		private readonly Dictionary<string, ConfigEntry<KeyCode>> _keyCodeConfigs = new Dictionary<string, ConfigEntry<KeyCode>>();

		public static ConfigManager Instance => _instance;

		public ConfigEntry<KeyCode> RecycleShortcut { get; private set; }

		public ConfigEntry<bool> 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<bool> RegisterBool(string section, string key, string description, bool defaultValue)
		{
			ConfigEntry<bool> val = _configFile.Bind<bool>(section, key, defaultValue, description);
			_boolConfigs[key] = val;
			return val;
		}

		public ConfigEntry<string> RegisterString(string section, string key, string description, string defaultValue)
		{
			ConfigEntry<string> val = _configFile.Bind<string>(section, key, defaultValue, description);
			_stringConfigs[key] = val;
			return val;
		}

		public ConfigEntry<KeyCode> RegisterKeyCode(string section, string key, string description, KeyCode defaultValue)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<KeyCode> val = _configFile.Bind<KeyCode>(section, key, defaultValue, description);
			_keyCodeConfigs[key] = val;
			return val;
		}

		public ConfigEntry<int> RegisterInt(string section, string key, string description, int defaultValue)
		{
			ConfigEntry<int> val = _configFile.Bind<int>(section, key, defaultValue, description);
			_intConfigs[key] = val;
			return val;
		}

		public ConfigEntry<int> 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<int> val = _configFile.Bind<int>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(minValue, maxValue), Array.Empty<object>()));
			_intConfigs[key] = val;
			return val;
		}

		public ConfigEntry<float> RegisterFloat(string section, string key, string description, float defaultValue)
		{
			ConfigEntry<float> val = _configFile.Bind<float>(section, key, defaultValue, description);
			_floatConfigs[key] = val;
			return val;
		}

		public ConfigEntry<float> 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<float> val = _configFile.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(minValue, maxValue), Array.Empty<object>()));
			_floatConfigs[key] = val;
			return val;
		}
	}
}