C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Oxide.Plugins
{
[Info("Better Charcoal", "Dana", "2.2.0")]
[Description("Say goodbye to charcoal shortages, hello to explosives!")]
public class BetterCharcoal : RustPlugin
{
#region Fields
private static BetterCharcoal _instance;
private static Configuration _config;
private CharcoalController _controller;
private Coroutine _coroutine;
#endregion Fields
#region Configuration
private class Configuration
{
[JsonProperty(PropertyName = "Version")]
public string Version { get; set; }
[JsonProperty(PropertyName = "Enable Charcoal Production")]
public bool EnableCharcoalProduction { get; set; }
[JsonProperty(PropertyName = "Charcoal Yield Chance")]
public int CharcoalYieldChance { get; set; }
[JsonProperty(PropertyName = "Lowest Charcoal Yield")]
public int LowestCharcoalYield { get; set; }
[JsonProperty(PropertyName = "Highest Charcoal Yield")]
public int HighestCharcoalYield { get; set; }
[JsonProperty(PropertyName = "Charcoal Production Rate")]
public int CharcoalProductionRate { get; set; }
[JsonProperty(PropertyName = "Fuel Consumption Rate")]
public int FuelConsumptionRate { get; set; }
[JsonProperty(PropertyName = "Enable Electric Furnace Charcoal Production")]
public bool EnableElectricFurnaceCharcoalProduction { get; set; }
[JsonProperty(PropertyName = "Electric Furnace Charcoal Yield Interval")]
public float ElectricFurnaceCharcoalYieldInterval { get; set; }
}
private Configuration GetDefaultConfig()
{
return new Configuration
{
Version = Version.ToString(),
EnableCharcoalProduction = true,
CharcoalYieldChance = 75,
LowestCharcoalYield = 1,
HighestCharcoalYield = 1,
CharcoalProductionRate = 1,
FuelConsumptionRate = 1,
EnableElectricFurnaceCharcoalProduction = false,
ElectricFurnaceCharcoalYieldInterval = 2f
};
}
protected override void LoadConfig()
{
base.LoadConfig();
_config = Config.ReadObject<Configuration>();
if (string.Compare(_config.Version, Version.ToString()) < 0)
UpdateConfig();
SaveConfig();
}
protected override void LoadDefaultConfig()
{
_config = GetDefaultConfig();
}
protected override void SaveConfig()
{
Config.WriteObject(_config, true);
}
private void UpdateConfig()
{
PrintWarning("Detected changes in configuration! Updating...");
Configuration defaultConfig = GetDefaultConfig();
if (string.Compare(_config.Version, "1.0.0") < 0)
_config = defaultConfig;
if (string.Compare(_config.Version, "2.1.0") < 0)
{
_config.ElectricFurnaceCharcoalYieldInterval = defaultConfig.ElectricFurnaceCharcoalYieldInterval;
}
if (string.Compare(_config.Version, "2.2.0") < 0)
{
_config.EnableElectricFurnaceCharcoalProduction = defaultConfig.EnableElectricFurnaceCharcoalProduction;
}
PrintWarning("Configuration update complete! Updated from version " + _config.Version + " to " + Version.ToString());
_config.Version = Version.ToString();
}
#endregion Configuration
#region Oxide Hooks
/// <summary>
/// Hook: Called when a plugin is being initialized./// </summary>
private void Init()
{
_instance = this;
_controller = new CharcoalController();
Permission.Register();
}
/// <summary>
/// Hook: Called after server startup is complete and awaits connections or when a plugin is hotloaded./// </summary>
private void OnServerInitialized()
{
StartCoroutine();
}
/// <summary>
/// Hook: Called when a plugin is being unloaded./// </summary>
private void Unload()
{
StopCoroutine();
_controller.CleanupOvens();
_config = null;
_instance = null;
}
/// <summary>
/// Hook: Called after any entity has spawned./// </summary>
/// <param name="oven"> The oven that has spawned.</param>
private void OnEntitySpawned(BaseOven oven)
{
_controller.Setup(oven);
}
/// <summary>
/// Hook: Called right before fuel starts being consumed in the oven./// </summary>
/// <param name="oven"> The oven being used.</param>
/// <param name="fuel"> The fuel item being consumed.</param>
/// <param name="burnable"> The burnable component of the fuel item.</param>
/// <returns> True or false if the fuel consumption should be skipped, null otherwise.</returns>
private object OnFuelConsume(BaseOven oven, Item fuel, ItemModBurnable burnable)
{
if (!OvenIsEligible(oven))
return null;
CharcoalComponent.GetComponent(oven)?.ConsumeFuel(fuel, burnable);
return true;
}
/// <summary>
/// Called when an oven is turned on or off./// </summary>
/// <param name="electricOven"> The electric oven being toggled.</param>
private void OnOvenToggle(ElectricOven electricOven)
{
if (!OvenIsEligible(electricOven) || !_config.EnableElectricFurnaceCharcoalProduction)
return;
bool ovenTurnedOn = electricOven.IsOn() ? false : true;
CharcoalComponent.GetComponent(electricOven).StateChanged(ovenTurnedOn);
}
#endregion Oxide Hooks
#region Coroutine
private void StartCoroutine()
{
_coroutine = ServerMgr.Instance.StartCoroutine(_controller.SetupOvens());
}
private void StopCoroutine()
{
if (!_coroutine.IsUnityNull())
{
ServerMgr.Instance.StopCoroutine(_coroutine);
_coroutine = null;
}
}
#endregion Coroutine
#region Controller
private class CharcoalController
{
private HashSet<CharcoalComponent> _components = new HashSet<CharcoalComponent>();
public void Register(CharcoalComponent component)
{
_components.Add(component);
}
public void Unregister(CharcoalComponent component)
{
_components.Remove(component);
}
public void Setup(BaseOven oven)
{
CharcoalComponent.InstallComponent(oven, this);
}
public IEnumerator SetupOvens()
{
WaitForSeconds waitDuration = ConVar.FPS.limit > 80 ? CoroutineEx.waitForSeconds(0.01f) : null;
foreach (var entity in BaseNetworkable.serverEntities)
{
BaseOven oven = entity as BaseOven;
if (!oven.IsValid())
continue;
CharcoalComponent.InstallComponent(oven, this);
if (oven is ElectricOven && oven.IsOn() && _config.EnableElectricFurnaceCharcoalProduction)
CharcoalComponent.GetComponent(oven).StateChanged(true);
yield return waitDuration;
}
}
public void CleanupOvens()
{
foreach (CharcoalComponent component in _components.ToList())
{
component.RemoveComponent();
}
}
}
#endregion Controller
#region Component
private class CharcoalComponent : FacepunchBehaviour
{
private BaseOven _oven;
private CharcoalController _controller;
private void OnDestroy()
{
_controller.Unregister(this);
}
public CharcoalComponent InitializeComponent(CharcoalController controller)
{
_oven = GetComponent<BaseOven>();
_controller = controller;
_controller.Register(this);
return this;
}
public static void InstallComponent(BaseOven oven, CharcoalController controller)
{
oven.gameObject.AddComponent<CharcoalComponent>().InitializeComponent(controller);
}
public static CharcoalComponent GetComponent(BaseOven oven)
{
return oven.gameObject.GetComponent<CharcoalComponent>();
}
public void RemoveComponent()
{
DestroyImmediate(this);
}
#region Furnace Functions
public void StateChanged(bool ovenTurnedOn)
{
if (ovenTurnedOn)
InvokeRepeating(YieldCharcoal, 1f, _config.ElectricFurnaceCharcoalYieldInterval);
else
CancelInvoke(YieldCharcoal);
}
private void YieldCharcoal()
{
if (_config.EnableCharcoalProduction && Random.Range(0, 100) < _config.CharcoalYieldChance)
{
Item item = ItemManager.CreateByName("charcoal", Random.Range(_config.LowestCharcoalYield, _config.HighestCharcoalYield) * _config.CharcoalProductionRate);
if (!item.MoveToContainer(_oven.inventory, -1, true, false, null))
{
_oven.OvenFull();
item.Drop(_oven.inventory.dropPosition, _oven.inventory.dropVelocity, default(Quaternion));
CancelInvoke(YieldCharcoal);
}
}
}
public void ConsumeFuel(Item fuel, ItemModBurnable burnable)
{
if (_oven.allowByproductCreation && burnable.byproductItem != null)
YieldCharcoal();
if (fuel.amount <= 1)
{
fuel.Remove(0f);
return;
}
fuel.UseItem(_config.FuelConsumptionRate);
fuel.fuel = burnable.fuelAmount;
fuel.MarkDirty();
}
#endregion Furnace Functions
}
#endregion Component
#region Helper Functions
/// <summary>
/// Finds a player by their unique player id and returns the BasePlayer object./// </summary>
/// <param name="playerId"> The id of the player to find.</param>
/// <returns> The BasePlayer object of the player with the specified id, or null if not found.</returns>
private BasePlayer FindPlayerById(ulong playerId)
{
return RelationshipManager.FindByID(playerId) ?? null;
}
/// <summary>
/// Determines if a oven is eligible for altered charcoal yield based on the owner's permission./// </summary>
/// <param name="oven"> The oven to check eligibility for.</param>
/// <returns> True if the oven is eligible, false otherwise.</returns>
private bool OvenIsEligible(BaseOven oven)
{
BasePlayer player = FindPlayerById(oven.OwnerID);
if (!player.IsValid())
return false;
if (!Permission.Verify(player))
return false;
return true;
}
#endregion Helper Functions
#region Permissions
/// <summary>
/// Contains utility methods for checking and registering plugin permissions./// </summary>
private static class Permission
{
public const string USE = "bettercharcoal.use";
public static void Register()
{
_instance.permission.RegisterPermission(USE, _instance);
}
public static bool Verify(BasePlayer player, string permissionName = USE)
{
if (_instance.permission.UserHasPermission(player.UserIDString, permissionName))
return true;
return false;
}
}
#endregion Permissions
}
}