C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*
* <----- End-User License Agreement ----->
* Copyright © 2024 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.*
*/
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Oxide.Plugins {
[Info("FurnaceUpgrades", "ifte", "2.5.3")]
[Description("Upgrade your furnaces and improve smelting!")]
internal class FurnaceUpgrades : RustPlugin {
/*------------------------------------
*
* FurnaceUpgrades by Ifte
* Original Author: Yun
* Support: https://discord.gg/cCWadjcapr
* Fiverr: https://www.fiverr.com/s/e2pkYY
* Eror404 not found
*
-------------------------------------*/
/* Version: 2.5.3
* - Fixed Console Spam from StackModifer(Codefling + Umod)
* - Added On new wipe its going to reset existing furnaces data
*/
/* Version: 2.5.2
* - Fixed for old update.*/
/* Version: 2.5.1
* - Fixed oven running after water gunned
*/
/* Version: 2.5.0
* - Fixed item not spliting on ovens
* - Fixed less fuel needed on higher smelting items
* - Adjusted Fuel Speed Multiplier and Smelting speed for vanilla
* - Fixed Furnace timings for vanilla
* - Fixed Notification
* - Fixed Stacks issues (Solution on Description)
*/
#region Fields
[PluginReference]
private Plugin Economics, ServerRewards, Toastify, Notify, ImageLibrary, StackModifier;
private static FurnaceUpgrades _instance;
private OvenController _controller;
private const string USE_PERMISSION = "FurnaceUpgrades.use";
private const string AUTO_FUEL_PERMISSION = "FurnaceUpgrades.autofuel";
private const string AUTO_SPLIT_PERMISSION = "FurnaceUpgrades.autosplit";
private readonly bool doDebug = false;
private readonly string[] _conflictPlugins = new string[] {
"StacksExtended", "StackModifier", "StackSizeController"
}
;
private readonly Dictionary<string, string> _ovensPrefab = new Dictionary<string, string>() {
{
"furnace", "assets/prefabs/deployable/furnace/furnace.prefab"
}
, {
"furnace.large", "assets/prefabs/deployable/furnace.large/furnace.large.prefab"
}
, {
"electric.furnace", "assets/prefabs/deployable/playerioents/electricfurnace/electricfurnace.deployed.prefab"
}
, {
"legacyfurnace", "assets/prefabs/deployable/legacyfurnace/legacy_furnace.prefab"
}
, {
"campfire", "assets/prefabs/deployable/campfire/campfire.prefab"
}
, {
"bbq", "assets/prefabs/deployable/bbq/bbq.deployed.prefab"
}
, {
"small.oil.refinery", "assets/prefabs/deployable/oil refinery/refinery_small_deployed.prefab"
}
}
;
private readonly Dictionary<string, string> _images = new Dictionary<string, string>() {
{
"legacyfurnace_image", "https://i.ibb.co/tLxgDP0/legacyfurnace-300x300.png"
}
}
;
private readonly Hash<ulong, BaseOven> _openModals = new Hash<ulong, BaseOven>();
private Coroutine _setupOvensCoroutine;
private class OvenSlot {
public Item Item;
public int? Position;
public int Index;
public int DeltaAmount;
}
private class OvenInfo {
public float ETA;
public float FuelNeeded;
}
private class OvenStatus {
public float SmeltingSpeed;
public float FuelSpeed;
public float ResourceOutput;
public float CharcoalMultiplier;
}
private class UpgradeResult {
public UpgradeResultType Type;
public int Cost;
public enum UpgradeResultType {
NotEnoughMoney, Success, MaxLevel,
}
public UpgradeResult(UpgradeResultType type, int cost) {
Type = type;
Cost = cost;
}
}
#region Enums
private enum FeatureType {
SmeltingSpeed, FuelSpeed, ResourceOutput, CharcoalMultiplier
}
private enum CurrencyType {
Item, Economics, ServerRewards
}
private enum NotificationPlugin {
None, Toastify, Notify
}
#endregion
#endregion
#region Data
private static Dictionary<ulong, FurnaceData> _furnacesData;
private enum FurnaceDataType {
Furnace, Item
}
private class FurnaceData {
public FurnaceDataType type;
public bool useAutoFuel = true;
public bool useAutoSplit = true;
public Levels levels = new Levels();
public class Levels {
public int smeltingSpeed;
public int fuelSpeed;
public int resourceOutput;
public int charcoalMultiplier;
}
}
private void LoadData() {
try {
_furnacesData = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, FurnaceData>>(Name);
}
catch {
_furnacesData = new Dictionary<ulong, FurnaceData>();
}
if (_furnacesData == null) _furnacesData = new Dictionary<ulong, FurnaceData>();
}
private void SaveData() {
Interface.Oxide.DataFileSystem.WriteObject(Name, _furnacesData);
}
#endregion
#region Configuration
private static Configuration _config;
private class UpgradeSettings {
[JsonProperty("Smelting speed")]
public Upgrade[] SmeltingSpeed {
get;
set;
}
[JsonProperty("Fuel speed")]
public Upgrade[] FuelSpeed {
get;
set;
}
[JsonProperty("Resource output multiplier")]
public Upgrade[] ResourceOutput {
get;
set;
}
[JsonProperty("Charcoal multiplier")]
public Upgrade[] CharcoalMultiplier {
get;
set;
}
public class Upgrade {
public int Cost {
get;
set;
}
public float Multiplier {
get;
set;
}
public Upgrade(int cost, float multiplier) {
Cost = cost;
Multiplier = multiplier;
}
}
}
private class DefaultSettings {
[JsonProperty("Smelting speed")]
public float SmeltingSpeed {
get;
set;
}
[JsonProperty("Fuel speed")]
public float FuelSpeed {
get;
set;
}
[JsonProperty("Resource output multiplier")]
public float ResourceOutput {
get;
set;
}
[JsonProperty("Charcoal multiplier")]
public float CharcoalMultiplier {
get;
set;
}
}
private class FeaturesSettings {
[JsonProperty("Smelting speed multiplier")]
public bool SmeltingSpeed {
get;
set;
}
[JsonProperty("Fuel speed")]
public bool FuelSpeed {
get;
set;
}
[JsonProperty("Resource output multiplier")]
public bool ResourceOutput {
get;
set;
}
[JsonProperty("Charcoal multiplier")]
public bool CharcoalMultiplier {
get;
set;
}
[JsonProperty("Auto split cookables")]
public bool AutoSplit {
get;
set;
}
[JsonProperty("Auto add fuel")]
public bool AutoFuel {
get;
set;
}
}
private class UISettings {
[JsonProperty("Disable status panel")]
public bool DisableStatusPanel {
get;
set;
}
[JsonProperty("Upgrade button")]
public BasicSettings UpgradeButton {
get;
set;
}
[JsonProperty("Upgrade button on electric furnaces")]
public BasicSettings UpgradeButtonElectricFurnace {
get;
set;
}
[JsonProperty("Status panel")]
public BasicSettings StatusPanel {
get;
set;
}
public class BasicSettings {
public string Anchor {
get;
set;
}
public string Offset {
get;
set;
}
[JsonProperty("Background color")]
public string BackgroundColor {
get;
set;
}
[JsonProperty("Font size")]
public int FontSize {
get;
set;
}
}
}
private class VisualSettings {
[JsonProperty("Use chat messages")]
public bool UseChatMessages {
get;
set;
}
[JsonProperty("Notification plugin (0 - None | 1 - Toastify | 2 - Notify)")]
public NotificationPlugin NotificationPlugin {
get;
set;
}
[JsonProperty("Toastify notification ID")]
public string ToastifyNotificationId {
get;
set;
}
[JsonProperty("Notify notification type")]
public int NotifyNotificationType {
get;
set;
}
[JsonProperty("Upgrade effect (empty = disabled)")]
public string UpgradeEffect {
get;
set;
}
}
private class CurrencySettings {
[JsonProperty("Currency type (0 - Scrap | 1 - Economics | 2 - Server Rewards)")]
public CurrencyType Type {
get;
set;
}
[JsonProperty("Currency item (if the currency type is '0')")]
public CurrencyItem Item {
get;
set;
}
public class CurrencyItem {
[JsonProperty("Short name")]
public string ShortName {
get;
set;
}
[JsonProperty("Skin ID")]
public ulong SkinID {
get;
set;
}
}
}
private class GeneralSettings {
[JsonProperty("Only the owner can upgrade the furnace")]
public bool OwnerOnly {
get;
set;
}
[JsonProperty("Only teammates can upgrade the furnace")]
public bool OnlyTeamMates {
get;
set;
}
[JsonProperty("Keep attributes when removing")]
public bool KeepAttributes {
get;
set;
}
}
private class Configuration {
[JsonProperty("General Settings")]
public GeneralSettings General {
get;
set;
}
[JsonProperty("Currency Settings")]
public CurrencySettings Currency {
get;
set;
}
[JsonProperty("Visual Settings")]
public VisualSettings Visual {
get;
set;
}
[JsonProperty("UI Settings")]
public UISettings UI {
get;
set;
}
[JsonProperty("Features Settings")]
public FeaturesSettings Features {
get;
set;
}
[JsonProperty("Default Settings")]
public DefaultSettings Defaults {
get;
set;
}
[JsonProperty("Upgrades Settings", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, UpgradeSettings> Upgrades {
get;
set;
}
public VersionNumber Version {
get;
set;
}
}
private Configuration GetBaseConfig() {
UpgradeSettings upgradeSettings = new UpgradeSettings() {
SmeltingSpeed = new UpgradeSettings.Upgrade[] {
new UpgradeSettings.Upgrade(100, 2f), new UpgradeSettings.Upgrade(200, 3f),
}
, CharcoalMultiplier = new UpgradeSettings.Upgrade[] {
new UpgradeSettings.Upgrade(100, 2f)
}
, FuelSpeed = new UpgradeSettings.Upgrade[] {
new UpgradeSettings.Upgrade(100, 2f)
}
, ResourceOutput = new UpgradeSettings.Upgrade[] {
new UpgradeSettings.Upgrade(100, 2f)
}
}
;
return new Configuration() {
General = new GeneralSettings() {
OwnerOnly = false, OnlyTeamMates = true, KeepAttributes = true
}
, Currency = new CurrencySettings() {
Type = CurrencyType.Item, Item = new CurrencySettings.CurrencyItem() {
ShortName = "scrap", SkinID = 0ul
}
}
, Visual = new VisualSettings() {
UseChatMessages = true, NotificationPlugin = NotificationPlugin.Toastify, ToastifyNotificationId = "success", NotifyNotificationType = 0, UpgradeEffect = "assets/bundled/prefabs/fx/build/promote_stone.prefab"
}
, UI = new UISettings() {
DisableStatusPanel = false, UpgradeButton = new UISettings.BasicSettings() {
Anchor = "0.5 0 0.5 0", Offset = "400 109.5 480 141.5", BackgroundColor = UIBuilder.Colors.GREEN, FontSize = 13
}
, UpgradeButtonElectricFurnace = new UISettings.BasicSettings() {
Anchor = "0.5 0 0.5 0", Offset = "492 354.5 572 386.5", BackgroundColor = UIBuilder.Colors.GREEN, FontSize = 13
}
, StatusPanel = new UISettings.BasicSettings() {
Anchor = "0.5 0 0.5 0", Offset = "193 17 420 103", BackgroundColor = "0.969 0.922 0.882 0.035", FontSize = 12
}
}
, Features = new FeaturesSettings() {
SmeltingSpeed = true, FuelSpeed = true, CharcoalMultiplier = true, ResourceOutput = true, AutoFuel = true, AutoSplit = true,
}
, Defaults = new DefaultSettings() {
FuelSpeed = 1f, CharcoalMultiplier = 1f, ResourceOutput = 1f, SmeltingSpeed = 1f
}
, Upgrades = _ovensPrefab.ToDictionary((x) => x.Key, (x) => upgradeSettings), Version = Version
}
;
}
#region Overrides
protected override void LoadDefaultConfig() => _config = GetBaseConfig();
protected override void LoadConfig() {
base.LoadConfig();
_config = Config.ReadObject<Configuration>();
if (_config.Version < Version) UpdateConfigValues();
Config.WriteObject(_config, true);
}
protected override void SaveConfig() => Config.WriteObject(_config, true);
private void UpdateConfigValues() {
PrintWarning("Your config file is outdated! Updating config values...");
if (_config.Version < new VersionNumber(2, 0, 3)) {
Configuration baseConfig = GetBaseConfig();
_config.General.OnlyTeamMates = baseConfig.General.OnlyTeamMates;
}
if (_config.Version < new VersionNumber(2, 0, 40)) {
Configuration baseconfig = GetBaseConfig();
_config.UI.UpgradeButtonElectricFurnace = baseconfig.UI.UpgradeButtonElectricFurnace;
}
_config.Version = Version;
PrintWarning("Config updated!");
}
#endregion
#endregion
#region Localization
private void SendNotification(BasePlayer player, string message, params object[] args) {
if (_config.Visual.NotificationPlugin == NotificationPlugin.None) return;
if (_config.Visual.NotificationPlugin == NotificationPlugin.Toastify) {
if (!Toastify) return;
Toastify.CallHook("SendToast", player, _config.Visual.ToastifyNotificationId, "UPGRADES", GetMessage(player, message, args), 3f);
}
else if (Notify) {
Notify.CallHook("SendNotify", player.UserIDString, _config.Visual.NotifyNotificationType, GetMessage(player, message, args));
}
}
private void SendMessage(BasePlayer player, string message, params object[] args) {
if (_config.Visual.UseChatMessages) player.ChatMessage($"{GetMessage(player, "Chat.Prefix")}: {GetMessage(player, message, args)}");
SendNotification(player, message, args);
}
private string GetMessage(BasePlayer player, string message, params object[] args) => string.Format(lang.GetMessage(message, this, player.UserIDString), args);
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string>() {
{
"Chat.Prefix", "<color=red>[FurnaceUpgrades]</color>"
}
, {
"Error.NoPermission", "You don't have permission to update this oven"
}
, {
"Error.NoPermission.AutoFuel", "You don't have permission to toggle the auto fuel."
}
, {
"Error.NoPermission.AutoSplit", "You don't have permission to toggle the auto split."
}
, {
"Error.NotEnoughMoney", "You don't have enough money to upgrade this attribute"
}
, {
"Error.OwnerOnly", "Only the owner can update the oven attributes."
}
, {
"Error.OwnerOnly.CanRemove", "Only the owner of a upgraded furnace can remove it"
}
, {
"Error.OnlyTeamMates", "Only the furnace owner's teammates can upgrade this furnace."
}
, {
"Error.OnlyTeamMates.CanRemove", "Only the furnace owner's teammates can remove this furnace"
}
, {
"Notification.SmeltingSpeedUpgraded", "The smelting speed has been upgraded for <color=red>-${0}</color>"
}
, {
"Notification.FuelSpeedUpgraded", "The fuel speed has been upgraded for <color=red>-${0}</color>"
}
, {
"Notification.ResourceOutputUpgraded", "The resource output multiplier has been upgraded for <color=red>-${0}</color>"
}
, {
"Notification.CharcoalMultiplierUpgraded", "The charcoal multiplier has been upgraded for <color=red>-${0}</color>"
}
, {
"UI.UpgradeButton", "UPGRADE"
}
, {
"UI.StatusTitle", "<b>STATUS:</b>"
}
, {
"UI.SmeltingSpeedStatus", "Smelting speed: <color=orange>{0}x</color>"
}
, {
"UI.FuelSpeedStatus", "Fuel speed: <color=orange>{0}x</color>"
}
, {
"UI.ResourceOutputStatus", "Resource output: <color=orange>{0}x</color>"
}
, {
"UI.CharcoalMultiplierStatus", "Charcoal multiplier: <color=orange>{0}x</color>"
}
, {
"UI.OptionsLabel", "<b>OPTIONS:</b>"
}
, {
"UI.NoOptionAvailable", "No option available =/"
}
, {
"UI.AutoFuelOptionLabel", "Auto add fuel"
}
, {
"UI.AutoSplitOptionLabel", "Auto split added ores"
}
, {
"UI.StatusTemplate", "<b>{0}x » <color=orange>{1}x</color></b>"
}
, {
"UI.StatusMaxLevel", "<b>MAX: <color=orange>{0}x</color></b>"
}
, {
"UI.UpgradeTemplate", "UPGRADE FOR ${0}"
}
, {
"UI.MaxLevelUpgrade", "✔ MAX LEVEL REACHED"
}
, {
"UI.SmeltingSpeed.Title", "<b>SMELTING SPEED</b>"
}
, {
"UI.SmeltingSpeed.Description", "Increases the speed of the ore smelting process"
}
, {
"UI.FuelSpeed.Title", "<b>FUEL SPEED</b>"
}
, {
"UI.FuelSpeed.Description", "Increases the speed at which fuel is burned"
}
, {
"UI.ResourceOutput.Title", "<b>RESOURCE OUTPUT</b>"
}
, {
"UI.ResourceOutput.Description", "Increases the resource production by tick"
}
, {
"UI.CharcoalMultiplier.Title", "<b>CHARCOAL MULTIPLIER</b>"
}
, {
"UI.CharcoalMultiplier.Description", "Increases the charcoal production by tick"
}
}
, this);
}
#endregion
#region Initialization
private void Init() {
Unsubscribe(nameof(CanMoveItem));
Unsubscribe(nameof(CanStackItem));
Unsubscribe(nameof(CanCombineDroppedItem));
Unsubscribe(nameof(OnEntityBuilt));
}
private void OnServerInitialized() {
_instance = this;
_controller = new OvenController();
LoadData();
CheckConflictPlugins();
if (_config.Features.AutoFuel || _config.Features.AutoSplit) {
Subscribe(nameof(CanMoveItem));
}
if (_config.General.KeepAttributes) {
Subscribe(nameof(OnEntityBuilt));
if (!StackModifier || !StackModifier.IsLoaded) {
Subscribe(nameof(CanStackItem));
Subscribe(nameof(CanCombineDroppedItem));
}
else {
PrintWarning("If the StackModifier plugin oven stack is greater than (1), upgrades will be lost, FurnaceUpgrades does not work correctly when changing the Furnace Stack using StackModifier!");
}
}
permission.RegisterPermission(USE_PERMISSION, this);
permission.RegisterPermission(AUTO_FUEL_PERMISSION, this);
permission.RegisterPermission(AUTO_SPLIT_PERMISSION, this);
if (ImageLibrary) {
ImageLibrary.CallHook("ImportImageList", Title, _images, 0ul, true);
var imageList = _ovensPrefab.Keys.Where((x) => x != "legacyfurnace").Select((x) => new KeyValuePair<string, ulong>(x, 0ul)).ToList();
ImageLibrary.CallHook("LoadImageList", Title, imageList);
}
_setupOvensCoroutine = ServerMgr.Instance.StartCoroutine(_controller.SetupOvens());
}
private void OnNewSave(string FileName) {
Puts("New save detected, resetting data...");
_furnacesData.Clear();
SaveData();
}
#endregion
#region Plugin loads check
private void OnPluginLoaded(Plugin plugin) {
if (_conflictPlugins.Contains(plugin.Name)) CheckConflictPlugins();
}
private void OnPluginUnloaded(Plugin plugin) => OnPluginLoaded(plugin);
private bool CheckConflictPlugins() {
string? conflictPlugin = _conflictPlugins.FirstOrDefault(x => plugins.Exists(x));
if (!string.IsNullOrEmpty(conflictPlugin)) {
Unsubscribe(nameof(CanStackItem));
Unsubscribe(nameof(CanCombineDroppedItem));
PrintWarning($"The CanStackItem, CanCombineDroppedItem hook's was unsubscribed due to conflicts with the '{conflictPlugin}' plugin");
return true;
}
else {
if (_config.General.KeepAttributes) {
Subscribe(nameof(CanStackItem));
Subscribe(nameof(CanCombineDroppedItem));
}
}
return false;
}
#endregion
#region Hooks
private void Unload() {
if (!_setupOvensCoroutine.IsUnityNull()) {
ServerMgr.Instance.StopCoroutine(_setupOvensCoroutine);
_setupOvensCoroutine = null;
}
foreach (var player in BasePlayer.activePlayerList) DestroyUI(player);
_controller.CleanupOvens();
_furnacesData = null;
_config = null;
_instance = null;
}
private void OnEntitySpawned(BaseOven oven) {
if (!oven.OwnerID.IsSteamId()) return;
if (!_ovensPrefab.ContainsValue(oven.PrefabName)) return;
_controller.InstallComponent(oven);
}
private object CanMoveItem(Item item, PlayerInventory playerLoot, ItemContainerId targetContainerId, int targetSlot, int amount) {
if (item == null || !playerLoot) return null;
if (!playerLoot.TryGetComponent<BasePlayer>(out var player)) return null;
BaseOven oven = playerLoot.loot.entitySource as BaseOven;
if (!oven) return null;
ItemContainer targetContainer = playerLoot.FindContainer(targetContainerId);
if (targetContainer != null && !(targetContainer?.entityOwner is BaseOven)) return null;
ItemContainer container = oven.inventory;
ItemContainer originalContainer = item.GetRootContainer();
if (container == null || originalContainer == null || container == originalContainer || originalContainer?.entityOwner is BaseOven) return null;
BaseOven.MinMax? allowedSlots = oven.GetAllowedSlots(item);
if (allowedSlots is null) return null;
for (int i = allowedSlots.Value.Min; i <= allowedSlots.Value.Max; i++) {
Item slot = oven.inventory.GetSlot(i);
if (slot != null && slot.info.shortname != item.info.shortname) return null;
}
if (!item.info.TryGetComponent<ItemModCookable>(out var cookable) || oven.IsOutputItem(item)) return null;
if (cookable.lowTemp > oven.cookingTemperature || cookable.highTemp < oven.cookingTemperature) return null;
if (!_furnacesData.TryGetValue(oven.net.ID.Value, out var furnaceData)) furnaceData = new FurnaceData();
// Move the splitted items
if (_config.Features.AutoSplit && furnaceData.useAutoSplit) MoveSplitItem(item, oven, amount);
// Auto add fuel
if (oven.allowByproductCreation && _config.Features.AutoFuel && furnaceData.useAutoFuel) NextTick(() => AutoAddFuel(playerLoot, oven));
return (_config.Features.AutoSplit && furnaceData.useAutoSplit) ? true : null;
}
#region Open/Close UI Hooks
private void OnLootEntity(BasePlayer player, BaseOven oven) {
if (player.IsInTutorial || !oven.OwnerID.IsSteamId()) return;
if (_config.General.OwnerOnly && oven.OwnerID != player.userID) return;
if (_config.General.OnlyTeamMates && oven.OwnerID != player.userID && !IsTeamMate(player, oven.OwnerID)) return;
if (!_ovensPrefab.ContainsValue(oven.PrefabName)) return;
if (!oven.HasComponent<OvenComponent>()) return;
ShowUpgradeButton(player, oven);
ShowOvenStatus(player, oven);
}
private void OnLootEntityEnd(BasePlayer player, BaseOven oven) {
DestroyUI(player);
}
#endregion
#region Oven Hooks
private object OnOvenToggle(BaseOven oven, BasePlayer player) {
if (!oven.TryGetComponent<OvenComponent>(out var component)) return null;
if (oven.IsOn()) component.StopCooking();
else {
oven.StopCooking();
component.StartCooking();
}
return false;
}
private object OnOvenStart(BaseOven oven) {
if (!oven.TryGetComponent<OvenComponent>(out var component)) return null;
component.StartCooking();
return false;
}
#endregion
#region Stack Fixes
private object CanStackItem(Item source, Item target) {
if (source == null || target == null) return null;
if (_furnacesData.ContainsKey(source.uid.Value) || _furnacesData.ContainsKey(target.uid.Value)) return false;
return null;
}
private object CanCombineDroppedItem(DroppedItem item, DroppedItem targetItem) => CanStackItem(item?.item, targetItem?.item);
#endregion
private void OnEntityBuilt(Planner planner, GameObject gameObject) {
BasePlayer player = planner.GetOwnerPlayer();
if (!player) return;
Item item = player.GetActiveItem();
if (item == null || !_ovensPrefab.ContainsKey(item.info.shortname)) return;
if (!gameObject.TryGetComponent<BaseOven>(out var oven)) return;
if (!_furnacesData.TryGetValue(item.uid.Value, out var itemData)) return;
_furnacesData.Remove(item.uid.Value);
_furnacesData[oven.net.ID.Value] = itemData;
itemData.type = FurnaceDataType.Furnace;
SaveData();
NextTick(() => {
if (oven.TryGetComponent<OvenComponent>(out var component)) component.UpdateProperties();
oven.inventory.Clear();
oven.inventory.MarkDirty();
}
);
}
private bool? CanPickupEntity(BasePlayer player, BaseOven oven) {
if (!oven.HasComponent<OvenComponent>()) return null;
if (!IsVanillaFurnace(oven) && _config.General.KeepAttributes) {
if (_config.General.OwnerOnly && oven.OwnerID != player.userID) {
SendMessage(player, "Error.OwnerOnly.CanRemove");
return false;
}
if (_config.General.OnlyTeamMates && oven.OwnerID != player.userID && !IsTeamMate(player, oven.OwnerID)) {
SendMessage(player, "Error.OnlyTeamMates.CanRemove");
return false;
}
}
if (TryGiveOvenWithAttributes(player, oven)) {
oven.Kill();
return false;
}
return null;
}
#region RemoverTool plugin
private object canRemove(BasePlayer player, BaseOven oven) {
if (!oven.HasComponent<OvenComponent>() || IsVanillaFurnace(oven)) return null;
if (_config.General.KeepAttributes) {
if (_config.General.OwnerOnly && oven.OwnerID != player.userID) return GetMessage(player, "Error.OwnerOnly.CanRemove");
if (_config.General.OnlyTeamMates && oven.OwnerID != player.userID && !IsTeamMate(player, oven.OwnerID)) return GetMessage(player, "Error.OnlyTeamMates.CanRemove");
}
return null;
}
private object OnRemovableEntityInfo(BaseEntity entity, BasePlayer player) {
if (!_config.General.KeepAttributes) return null;
if (!(entity is BaseOven oven) || !oven.HasComponent<OvenComponent>()) return null;
if (!_furnacesData.TryGetValue(oven.net.ID.Value, out var furnaceData)) return null;
string itemName = _ovensPrefab.First((x) => x.Value == entity.PrefabName).Key;
ItemDefinition itemDef = ItemManager.FindItemDefinition(itemName);
if (!itemDef) return null;
string displayName = $"{itemDef.displayName.english} - UPGRADED";
return new Dictionary<string, object>() {
{
"DisplayName", displayName
}
, {
"Refund", new Dictionary<string, object> {
{
"furnaceupgrades.furnace", new Dictionary<string, object> {
{
"Amount", 1
}
, {
"DisplayName", displayName
}
}
}
}
}
}
;
}
private object OnRemovableEntityGiveRefund(BaseEntity entity, BasePlayer player, string itemName) {
if (!(entity is BaseOven oven) || !oven.HasComponent<OvenComponent>()) return null;
if (itemName != "furnaceupgrades.furnace") return null;
if (!TryGiveOvenWithAttributes(player, oven)) return false;
return null;
}
#endregion
#region BuildTools Plugin
private object CanBuildToolsGiveRefund(BasePlayer player, BaseEntity entity) {
if (!(entity is BaseOven oven) || !oven.HasComponent<OvenComponent>()) return null;
if (TryGiveOvenWithAttributes(player, oven)) return false;
return null;
}
#endregion
#endregion
#region Functions
private void MoveSplitItem(Item item, BaseOven oven, int splitAmount) {
ItemContainer container = oven.inventory;
int numOreSlots = oven.inputSlots;
int totalMoved = 0;
int itemAmount = item.amount > splitAmount ? splitAmount : item.amount;
int totalAmount = Math.Min(itemAmount + container.itemList.Where(slotItem => slotItem.info == item.info).Take(numOreSlots).Sum(slotItem => slotItem.amount), Math.Abs(item.info.stackable * numOreSlots));
if (numOreSlots <= 0) {
return;
}
int totalStackSize = Math.Min(totalAmount / numOreSlots, item.info.stackable);
int remaining = totalAmount - totalAmount / numOreSlots * numOreSlots;
List<int> addedSlots = Pool.Get<List<int>>();
List<OvenSlot> ovenSlots = Pool.Get<List<OvenSlot>>();
for (int i = 0; i < numOreSlots; ++i) {
Item existingItem;
int slot = FindMatchingSlotIndex(oven, container, out existingItem, item.info, addedSlots);
if (slot == -1) {
return;
}
addedSlots.Add(slot);
OvenSlot ovenSlot = new OvenSlot {
Position = existingItem?.position, Index = slot, Item = existingItem
}
;
int currentAmount = existingItem?.amount ?? 0;
int missingAmount = totalStackSize - currentAmount + (i < remaining ? 1 : 0);
ovenSlot.DeltaAmount = missingAmount;
if (currentAmount + missingAmount <= 0) continue;
ovenSlots.Add(ovenSlot);
}
Pool.FreeUnmanaged(ref addedSlots);
foreach (OvenSlot slot in ovenSlots) {
if (slot.Item == null) {
Item newItem = ItemManager.Create(item.info, slot.DeltaAmount, item.skin);
slot.Item = newItem;
newItem.MoveToContainer(container, slot.Position ?? slot.Index);
}
else {
slot.Item.amount += slot.DeltaAmount;
}
totalMoved += slot.DeltaAmount;
}
container.MarkDirty();
Pool.FreeUnmanaged(ref ovenSlots);
if (totalMoved >= item.amount) {
item.Remove();
item.GetRootContainer()?.MarkDirty();
return;
}
else {
item.amount -= totalMoved;
item.GetRootContainer()?.MarkDirty();
return;
}
}
private void AutoAddFuel(PlayerInventory playerInventory, BaseOven oven) {
OvenInfo ovenInfo = GetOvenInfo(oven);
int neededFuel = (int)Math.Ceiling(ovenInfo.FuelNeeded) - oven.inventory.GetAmount(oven.fuelType.itemid, false);
var playerFuel = playerInventory.FindItemsByItemID(oven.fuelType.itemid);
if (neededFuel <= 0 || playerFuel.Count <= 0) return;
int fuelSlotIndex = 0;
foreach (var item in playerFuel) {
Item existingFuel = oven.inventory.GetSlot(fuelSlotIndex);
if (existingFuel != null && existingFuel.amount >= existingFuel.info.stackable) {
if (fuelSlotIndex < oven.fuelSlots) fuelSlotIndex++;
else break;
}
Item largestFuelStack = oven.inventory.itemList.Where(x => x.info == oven.fuelType).OrderByDescending(x => item.amount).FirstOrDefault();
int toTake = Math.Min(neededFuel, (oven.fuelType.stackable * oven.fuelSlots) - (largestFuelStack?.amount ?? 0));
if (toTake <= 0) break;
if (toTake > item.amount) toTake = item.amount;
neededFuel -= toTake;
int currentFuelAmount = oven.inventory.GetAmount(oven.fuelType.itemid, false);
if (currentFuelAmount >= oven.fuelType.stackable * oven.fuelSlots) break;
if (toTake >= item.amount) {
item.MoveToContainer(oven.inventory, fuelSlotIndex);
}
else {
Item splitItem = item.SplitItem(toTake);
if (!splitItem.MoveToContainer(oven.inventory, fuelSlotIndex)) break;
}
if (neededFuel <= 0) break;
}
}
private UpgradeResult TryUpgradeAttribute(BasePlayer player, BaseOven oven, FeatureType type) {
UpgradeSettings.Upgrade nextUpgrade = GetNextUpgrade(oven, type);
if (nextUpgrade == null) return new UpgradeResult(UpgradeResult.UpgradeResultType.MaxLevel, 0);
if (!TryTakeMoney(player, nextUpgrade.Cost)) return new UpgradeResult(UpgradeResult.UpgradeResultType.NotEnoughMoney, nextUpgrade.Cost);
if (!_furnacesData.TryGetValue(oven.net.ID.Value, out var furnaceData)) furnaceData = new FurnaceData();
switch (type) {
case FeatureType.SmeltingSpeed : furnaceData.levels.smeltingSpeed++;
break;
case FeatureType.FuelSpeed : furnaceData.levels.fuelSpeed++;
break;
case FeatureType.ResourceOutput : furnaceData.levels.resourceOutput++;
break;
case FeatureType.CharcoalMultiplier : furnaceData.levels.charcoalMultiplier++;
break;
}
_furnacesData[oven.net.ID.Value] = furnaceData;
SaveData();
return new UpgradeResult(UpgradeResult.UpgradeResultType.Success, nextUpgrade.Cost);
}
private bool TryGiveOvenWithAttributes(BasePlayer player, BaseOven oven) {
string ovenName = _ovensPrefab.FirstOrDefault((x) => x.Value == oven.PrefabName).Key;
if (string.IsNullOrEmpty(ovenName)) return false;
if (!_furnacesData.TryGetValue(oven.net.ID.Value, out var furnaceData)) return false;
if (!_config.General.KeepAttributes) {
_furnacesData.Remove(oven.net.ID.Value);
SaveData();
return false;
}
Item item = ItemManager.CreateByName(ovenName, 1, oven.skinID);
if (item == null) return false;
item.name = $"{item.info.displayName.english} - UPGRADED";
_furnacesData.Remove(oven.net.ID.Value);
_furnacesData[item.uid.Value] = furnaceData;
furnaceData.type = FurnaceDataType.Item;
SaveData();
if (!item.MoveToContainer(player.inventory.containerBelt, -1, false) && !item.MoveToContainer(player.inventory.containerMain, -1, false)) item.Drop(player.inventory.containerMain.dropPosition, player.inventory.containerMain.dropVelocity);
return true;
}
#endregion
#region Helpers
private BaseOven GetOvenById(NetworkableId ovenId) {
return BaseNetworkable.serverEntities.Find(ovenId) as BaseOven;
}
private bool TryTakeMoney(BasePlayer player, int amount) {
switch (_config.Currency.Type) {
case CurrencyType.Economics : return Economics.Call<bool>("Withdraw", player.UserIDString, (double)amount);
case CurrencyType.ServerRewards : {
int balance = ServerRewards.Call<int>("CheckPoints", player.userID);
if (balance < amount) return false;
object result = ServerRewards.CallHook("TakePoints", player.userID, amount);
return result is bool ? (bool)result : false;
}
default : {
int acc = 0;
List<Item> toTake = Pool.Get<List<Item>>();
foreach (var item in player.inventory.containerMain.itemList) {
if (item.info.shortname == _config.Currency.Item.ShortName && item.skin == _config.Currency.Item.SkinID) {
acc += item.amount;
toTake.Add(item);
if (acc >= amount) break;
}
}
// Process containerMain if still required
if (acc < amount) {
foreach (var item in player.inventory.containerBelt.itemList) {
if (item.info.shortname == _config.Currency.Item.ShortName && item.skin == _config.Currency.Item.SkinID) {
acc += item.amount;
toTake.Add(item);
if (acc >= amount) break;
}
}
}
if (acc < amount) {
Pool.FreeUnmanaged(ref toTake);
return false;
}
int remaining = amount;
foreach (var item in toTake) {
if (item.amount > remaining) {
item.UseItem(remaining);
remaining = 0;
}
else {
remaining -= item.amount;
item.Remove();
}
item.MarkDirty();
if (remaining < 1) break;
}
Pool.FreeUnmanaged(ref toTake);
return true;
}
}
}
private OvenStatus GetOvenStatus(BaseOven oven) {
return new OvenStatus() {
SmeltingSpeed = GetCurrentUpgrade(oven, FeatureType.SmeltingSpeed)?.Multiplier ?? _config.Defaults.SmeltingSpeed, FuelSpeed = GetCurrentUpgrade(oven, FeatureType.FuelSpeed)?.Multiplier ?? _config.Defaults.FuelSpeed, ResourceOutput = GetCurrentUpgrade(oven, FeatureType.ResourceOutput)?.Multiplier ?? _config.Defaults.ResourceOutput, CharcoalMultiplier = GetCurrentUpgrade(oven, FeatureType.CharcoalMultiplier)?.Multiplier ?? _config.Defaults.CharcoalMultiplier
}
;
}
private UpgradeSettings.Upgrade GetCurrentUpgrade(BaseOven oven, FeatureType type) {
string ovenName = _ovensPrefab.FirstOrDefault((x) => x.Value == oven.PrefabName).Key;
_furnacesData.TryGetValue(oven.net.ID.Value, out var furnaceData);
int currentLevel = type switch {
FeatureType.SmeltingSpeed => furnaceData?.levels.smeltingSpeed ?? 0, FeatureType.FuelSpeed => furnaceData?.levels.fuelSpeed ?? 0, FeatureType.ResourceOutput => furnaceData?.levels.resourceOutput ?? 0, _ => furnaceData?.levels.charcoalMultiplier ?? 0,
}
;
UpgradeSettings settings = _config.Upgrades[ovenName];
UpgradeSettings.Upgrade[] upgrades = type switch {
FeatureType.SmeltingSpeed => settings.SmeltingSp
// ... [Code preview truncated due to length. Full source in attached file] ...