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<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> 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<CodeInstruction> ReplaceDenominator(IEnumerable<CodeInstruction> instructions, string target)
{
List<CodeInstruction> 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<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> 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<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> 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<bool> _enabled;
internal static bool Enabled
{
get
{
if (_enabled != null)
{
return _enabled.Value;
}
return true;
}
}
internal static void Bind(ConfigFile config)
{
_enabled = config.Bind<bool>("Full Recycle", "EnableFullRecycle", true, I18n.Localizer.Config("config.enabled", 10, "Full Recycle", "config.section", 10, (AcceptableValueBase)null));
}
}
}