C#:
/*
* <----- End-User License Agreement ----->
*
* Copyright ©2026 Iftebinjan
* Devoloper: Iftebinjan (Contact: https://discord.gg/HFaGs8YwsH)
*
* You may not copy, modify, merge, publish, distribute, sublicense, or sell copies of This Software without the Developer’s consent
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* <----- End-User License Agreement ----->
*/
// Reference: 0Harmony
using HarmonyLib;
using Newtonsoft.Json;
using Oxide.Core;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("QuickSmelt", "ifte", "1.0.1")]
[Description("A simple furnce speed, output and charcoal multipler using harmony.")]
public class QuickSmelt : RustPlugin
{
/*------------------------------------
*
* QuickSmelt by Ifte
* Support: https://discord.gg/cCWadjcapr
* Fiverr: https://www.fiverr.com/s/e2pkYY
* Eror404 not found
*
------------------------------------*/
#region Vars
private static QuickSmelt _plugin;
private Harmony _harmony;
#endregion
#region Config
private Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Speed Multipliers")]
public Dictionary<string, int> SpeedMultipliers { get; set; }
[JsonProperty(PropertyName = "Output Multipliers")]
public Dictionary<string, int> OutputMultipliers { get; set; }
[JsonProperty(PropertyName = "Charcoal Multipliers")]
public Dictionary<string, int> CharcoalMultipliers { get; set; }
public VersionNumber Version { get; set; }
}
private Configuration GetBaseConfig()
{
return new Configuration
{
SpeedMultipliers = new Dictionary<string, int>()
{
["*"] = 1,
["shortprefabname"] = 1,
},
OutputMultipliers = new Dictionary<string, int>()
{
["*"] = 1,
["shortprefabname"] = 1,
},
CharcoalMultipliers = new Dictionary<string, int>()
{
["*"] = 1,
["shortprefabname"] = 1,
},
Version = Version
};
}
protected override void LoadConfig()
{
base.LoadConfig();
_config = Config.ReadObject<Configuration>();
if (_config.Version < Version)
UpdateConfigValues();
Config.WriteObject(_config, true);
}
protected override void LoadDefaultConfig()
=> _config = GetBaseConfig();
protected override void SaveConfig()
=> Config.WriteObject(_config, true);
private void UpdateConfigValues()
{
PrintWarning("Your config file is outdated! Updating config values...");
Configuration baseConfig = GetBaseConfig();
_config.Version = Version;
PrintWarning($"Config updated to {_config.Version}");
}
#endregion
#region Init
private void OnServerInitialized()
{
_plugin = this;
_harmony = new Harmony($"{Name}_ifte_{Version.Major}_{Version.Minor}_{Version.Patch}");
_harmony.Patch(AccessTools.Method(typeof(ItemModCookable), "CycleCooking"), transpiler: new HarmonyMethod(typeof(CookingPatch), "UpgradeFurnace"));
_harmony.Patch(AccessTools.Method(typeof(BaseOven), "ConsumeFuel"), transpiler: new HarmonyMethod(typeof(CharcoalPatch), "UpgradeFurnace"));
}
private void Unload()
{
_harmony.UnpatchAll($"{Name}_ifte_{Version.Major}_{Version.Minor}_{Version.Patch}");
_plugin = null;
}
#endregion
#region Harmony Patch
public class CookingPatch
{
public static IEnumerable<CodeInstruction> UpgradeFurnace(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> codes = new List<CodeInstruction>(instructions);
Type pluginType = typeof(CookingPatch).DeclaringType;
MethodInfo getSmeltingSpeed = AccessTools.Method(pluginType, "GetSmeltingSpeed", new[] { typeof(BaseOven) });
MethodInfo getResourcesOutput = AccessTools.Method(pluginType, "GetResourcesOutput", new[] { typeof(BaseOven) });
int ovenStoreIndex = -1;
object ovenLocal = null;
object countLocal = null;
for (int i = 0; i < codes.Count - 2; i++)
{
if (codes[i].opcode == OpCodes.Isinst &&
(codes[i].operand as Type) == typeof(BaseOven) &&
codes[i + 1].IsStloc() &&
codes[i + 2].IsLdloc())
{
ovenStoreIndex = i + 1;
ovenLocal = codes[i + 1].operand;
countLocal = codes[i + 2].operand;
break;
}
}
if (ovenStoreIndex != -1 && ovenLocal != null && countLocal != null)
{
codes.InsertRange(ovenStoreIndex + 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, countLocal),
new CodeInstruction(OpCodes.Ldloc_S, ovenLocal),
new CodeInstruction(OpCodes.Call, getSmeltingSpeed),
new CodeInstruction(OpCodes.Mul),
new CodeInstruction(OpCodes.Stloc_S, countLocal)
});
}
if (ovenLocal != null)
{
for (int i = 0; i < codes.Count - 3; i++)
{
if (codes[i].opcode == OpCodes.Ldfld &&
(codes[i].operand as FieldInfo)?.Name == "amountOfBecome" &&
codes[i + 1].IsLdloc() &&
codes[i + 2].opcode == OpCodes.Conv_R4 &&
codes[i + 3].opcode == OpCodes.Mul)
{
// result *= (float)GetResourcesOutput(oven)
codes.InsertRange(i + 4, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, ovenLocal),
new CodeInstruction(OpCodes.Call, getResourcesOutput),
new CodeInstruction(OpCodes.Conv_R4),
new CodeInstruction(OpCodes.Mul)
});
break;
}
}
}
return codes;
}
}
public class CharcoalPatch
{
public static IEnumerable<CodeInstruction> UpgradeFurnace(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> ilList = new(instructions);
MethodInfo getCharcoalRate = AccessTools.Method(typeof(BaseOven), nameof(BaseOven.GetCharcoalRate));
foreach (CodeInstruction instruction in ilList)
{
MethodInfo methodInfo = instruction.operand as MethodInfo;
if (methodInfo == getCharcoalRate)
{
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(QuickSmelt), nameof(GetCharcoalRate)));
}
else
{
yield return instruction;
}
}
}
}
private static int GetMultiplier(Dictionary<string, int> multipliers, BaseOven instance)
{
if (instance == null || multipliers == null)
return 1;
if (!string.IsNullOrEmpty(instance.ShortPrefabName) &&
multipliers.TryGetValue(instance.ShortPrefabName, out int specific))
return Mathf.Max(1, specific);
if (multipliers.TryGetValue("*", out int wildcard))
return Mathf.Max(1, wildcard);
return 1;
}
protected static int GetSmeltingSpeed(BaseOven instance)
{
if (_plugin?._config == null)
return 1;
return GetMultiplier(_plugin._config.SpeedMultipliers, instance);
}
protected static int GetResourcesOutput(BaseOven instance)
{
if (_plugin?._config == null)
return 1;
return GetMultiplier(_plugin._config.OutputMultipliers, instance);
}
protected static int GetCharcoalRate(BaseOven instance)
{
if (_plugin?._config == null)
return 1;
return GetMultiplier(_plugin._config.CharcoalMultipliers, instance);
}
#endregion
}
}