using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FullRecycle.Configuration; using FullRecycle.Localization; using FullRecycle.Runtime; using Fusion; using HarmonyLib; using ModSettingsMenu.Api; using SunkenlandLocalizationAPI.Api; using UnityEngine; using cfg; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("FullRecycle")] [assembly: AssemblyDescription("Full recycle mod for Sunkenland by Ice Box Studio")] [assembly: AssemblyCompany("Ice Box Studio")] [assembly: AssemblyProduct("FullRecycle")] [assembly: AssemblyCopyright("Copyright © 2026 Ice Box Studio All rights reserved.")] [assembly: ComVisible(false)] [assembly: Guid("5f7cdd9d-21b1-4bb2-9bcb-8c44f9f7629a")] [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 FullRecycle { [BepInPlugin("IceBoxStudio.Sunkenland.FullRecycle", "FullRecycle", "1.0.0")] [BepInDependency("IceBoxStudio.Sunkenland.ModSettingsMenu", "1.2.0")] [BepInDependency("IceBoxStudio.Sunkenland.LocalizationAPI", "1.1.0")] public sealed class FullRecycle : BaseUnityPlugin { private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; LocalizationApi.LanguageChanged += OnLanguageChanged; try { Log.LogInfo((object)"============================================="); Log.LogInfo((object)("FullRecycle " + I18n.Text("plugin.initializing"))); Log.LogInfo((object)(I18n.Text("plugin.author_prefix") + "Ice Box Studio(https://steamcommunity.com/id/ibox666/)")); ConfigManager.Bind(((BaseUnityPlugin)this).Config); RegisterSettings(); _harmony = new Harmony("IceBoxStudio.Sunkenland.FullRecycle"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)("FullRecycle " + I18n.Text("plugin.initialized"))); Log.LogInfo((object)"============================================="); } catch (Exception arg) { Log.LogError((object)$"Failed to initialize Full Recycle: {arg}"); } } private static void RegisterSettings() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown ModSettingsRegistry.Register("IceBoxStudio.Sunkenland.FullRecycle", new ModSettingsModOptions { Name = "Full Recycle", LocalizedName = () => I18n.Text("mod.name"), Description = I18n.Text("mod.description"), Author = "Ice Box Studio", Version = "1.0.0", NexusModsId = 83, ThunderstoreTeam = "Ice_Box_Studio_Sunkenland", ThunderstoreModName = "FullRecycle" }); } private static void OnLanguageChanged(string language) { RegisterSettings(); } } public static class PluginInfo { public const string PLUGIN_GUID = "IceBoxStudio.Sunkenland.FullRecycle"; public const string PLUGIN_NAME = "FullRecycle"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace FullRecycle.Runtime { internal static class RecoveryCalculator { internal static int GetCraftingRecoveryDivisor() { if (!ConfigManager.Enabled) { return 2; } return 1; } } internal static class RecycleChanceRuntime { internal static float GetProbabilityDenominator() { if (!RecycleContext.IsActive || !ConfigManager.Enabled) { return 10000f; } return 0.0001f; } } internal static class RecycleContext { [ThreadStatic] private static int _depth; internal static bool IsActive => _depth > 0; internal static bool Enter(bool pass, int itemId) { if (!pass || !ConfigManager.Enabled || (Object)(object)RM.code == (Object)null || RM.code.ItemDictionary == null) { return false; } if (!RM.code.ItemDictionary.TryGetValue(itemId, out var value) || value == (Item)null || value.RecyclingDropID == 0) { return false; } _depth++; return true; } internal static void Exit() { if (_depth > 0) { _depth--; } } } } namespace FullRecycle.Patches { [HarmonyPatch(typeof(DecomposeTable), "RPC_OnConfirmTakeItem", new Type[] { typeof(PlayerRef), typeof(bool), typeof(int), typeof(int), typeof(int[]) })] internal static class DecomposeTableFullRecoveryPatch { [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { List list = instructions.ToList(); FieldInfo fieldInfo = AccessTools.Field(typeof(CraftingItemRequirement), "amount"); MethodInfo methodInfo = AccessTools.Method(typeof(RecoveryCalculator), "GetCraftingRecoveryDivisor", (Type[])null, (Type[])null); if (fieldInfo == null || methodInfo == null) { throw new InvalidOperationException("FullRecycle could not resolve the crafting recovery patch members."); } int num = 0; for (int i = 0; i < list.Count - 2; i++) { if (!(list[i].opcode != OpCodes.Ldfld) && object.Equals(list[i].operand, fieldInfo) && !(list[i + 1].opcode != OpCodes.Ldc_I4_2) && (!(list[i + 2].opcode != OpCodes.Div) || !(list[i + 2].opcode != OpCodes.Div_Un))) { list[i + 1].opcode = OpCodes.Call; list[i + 1].operand = methodInfo; num++; } } if (num != 1) { throw new InvalidOperationException($"FullRecycle expected one crafting recovery division, found {num}."); } return list; } } [HarmonyPatch(typeof(DecomposeTable), "RPC_OnConfirmTakeItem", new Type[] { typeof(PlayerRef), typeof(bool), typeof(int), typeof(int), typeof(int[]) })] internal static class DecomposeTableRecycleScopePatch { [HarmonyPrefix] private static void Prefix(bool __1, int __2, out bool __state) { __state = RecycleContext.Enter(__1, __2); } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception, bool __state) { if (__state) { RecycleContext.Exit(); } return __exception; } } internal static class DropChancePatchHelper { internal static IEnumerable ReplaceDenominator(IEnumerable instructions, string target) { List list = instructions.ToList(); MethodInfo methodInfo = AccessTools.Method(typeof(RecycleChanceRuntime), "GetProbabilityDenominator", (Type[])null, (Type[])null); if (methodInfo == null) { throw new InvalidOperationException("FullRecycle could not resolve the recycle chance helper."); } int num = 0; foreach (CodeInstruction item in list) { if (!(item.opcode != OpCodes.Ldc_R4) && item.operand is float num2 && !(Math.Abs(num2 - 10000f) > 0.001f)) { item.opcode = OpCodes.Call; item.operand = methodInfo; num++; } } if (num != 1) { throw new InvalidOperationException($"FullRecycle expected one recycle chance denominator in {target}, found {num}."); } return list; } } [HarmonyPatch(typeof(DropManager), "GetDroppedItems", new Type[] { typeof(int) })] internal static class DropManagerGroupChancePatch { [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { return DropChancePatchHelper.ReplaceDenominator(instructions, "DropManager.GetDroppedItems"); } } [HarmonyPatch(typeof(DropManager), "GetDropPoolDataByID", new Type[] { typeof(Tables), typeof(int) })] internal static class DropManagerPoolChancePatch { [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { return DropChancePatchHelper.ReplaceDenominator(instructions, "DropManager.GetDropPoolDataByID"); } } } namespace FullRecycle.Localization { internal static class I18n { private const string FileName = "FullRecycle.Localization.json"; private static readonly ModLocalizer _localizer = Load(); internal static ModLocalizer Localizer => _localizer; internal static string Text(string key, params object[] args) { return _localizer.GetLocalizedText(key, args); } private static ModLocalizer Load() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); ModLocalizer obj = LocalizationApi.For("IceBoxStudio.Sunkenland.FullRecycle"); obj.RegisterJson(Path.Combine(directoryName, "FullRecycle.Localization.json")); return obj; } } } namespace FullRecycle.Configuration { internal static class ConfigManager { private const string Section = "Full Recycle"; private static ConfigEntry _enabled; internal static bool Enabled { get { if (_enabled != null) { return _enabled.Value; } return true; } } internal static void Bind(ConfigFile config) { _enabled = config.Bind("Full Recycle", "EnableFullRecycle", true, I18n.Localizer.Config("config.enabled", 10, "Full Recycle", "config.section", 10, (AcceptableValueBase)null)); } } }