C#:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Self Watering Planters", "ShadowStrike", "4.1.0")]
[Description("Automatically waters planters at configurable intervals")]
class SelfWateringPlanters : RustPlugin
{
private const string PermissionUse = "selfwateringplanters.use";
private PluginConfig config;
private Timer waterTimer;
private readonly HashSet<PlanterBox> planters = new HashSet<PlanterBox>();
private bool isProcessing;
#region Configuration
class PluginConfig
{
public float TickIntervalSeconds { get; set; } = 60f;
public float TargetSaturationFraction { get; set; } = 0.95f;
public int MaxMillisecondsPerFrame { get; set; } = 5;
public bool DebugMode { get; set; } = false;
public bool RequirePermission { get; set; } = false;
}
protected override void LoadDefaultConfig() => config = new PluginConfig();
protected override void LoadConfig()
{
base.LoadConfig();
config = Config.ReadObject<PluginConfig>() ?? new PluginConfig();
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config, true);
#endregion
#region Oxide Hooks
void Init() => permission.RegisterPermission(PermissionUse, this);
void OnServerInitialized() => waterTimer = timer.Every(Mathf.Max(5f, config.TickIntervalSeconds), StartWateringProcess);
void OnEntitySpawned(PlanterBox planter) { if (planter != null) planters.Add(planter); }
void OnEntityKill(PlanterBox planter) => planters.Remove(planter);
void Unload()
{
waterTimer?.Destroy();
planters.Clear();
}
#endregion
#region Core Logic
void StartWateringProcess()
{
if (isProcessing) return;
ServerMgr.Instance.StartCoroutine(WaterPlantersCoroutine());
}
IEnumerator WaterPlantersCoroutine()
{
isProcessing = true;
planters.RemoveWhere(p => p == null || p.IsDestroyed);
if (planters.Count == 0)
{
isProcessing = false;
yield break;
}
float targetFraction = Mathf.Clamp01(config.TargetSaturationFraction);
int watered = 0;
var watch = System.Diagnostics.Stopwatch.StartNew();
foreach (var planter in planters)
{
if (planter == null || planter.IsDestroyed) continue;
if (config.RequirePermission && !HasPermission(planter.OwnerID))
continue;
int targetWater = Mathf.RoundToInt(planter.idealSaturation * targetFraction);
if (planter.soilSaturation < targetWater)
{
planter.soilSaturation = targetWater;
planter.SendNetworkUpdate();
watered++;
}
if (watch.ElapsedMilliseconds > config.MaxMillisecondsPerFrame)
{
yield return null;
watch.Restart();
}
}
if (config.DebugMode)
Puts($"Watered {watered}/{planters.Count} planters in {watch.ElapsedMilliseconds}ms");
isProcessing = false;
}
bool HasPermission(ulong ownerId)
{
if (ownerId == 0) return false;
return permission.UserHasPermission(ownerId.ToString(), PermissionUse);
}
#endregion
}
}