C#:
// #define DEBUG
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Plugins;
using HarmonyLib;
namespace Oxide.Plugins
{
[Info("Auto Plant", "Egor Blagov / rostov114", "2.0.1")]
[Description("Automation of your plantations")]
class AutoPlant : RustPlugin
{
#region Variables
public static AutoPlant _instance;
private List<ulong> _activeUse = new List<ulong>();
#endregion
#region Configuration
private Configuration _config;
public class Configuration
{
[JsonProperty(PropertyName = "Auto Gather permission")]
public string autoGather = "autoplant.gather.use";
[JsonProperty(PropertyName = "Auto Cutting permission")]
public string autoCutting = "autoplant.cutting.use";
[JsonProperty(PropertyName = "Auto Remove Dying permission")]
public string autoDying = "autoplant.removedying.use";
[JsonProperty(PropertyName = "Auto fertilizer permission")]
public string autoFertilizer = "autoplant.fertilizer.use";
[JsonProperty(PropertyName = "Auto fertilizer configuration")]
public FertilizerConfiguration fertilizer = new FertilizerConfiguration();
public class FertilizerConfiguration
{
[JsonProperty(PropertyName = "Maximum distance from the PlanterBox")]
public int maxDistance = 5;
[JsonProperty(PropertyName = "Default fertilizer amount")]
public int defaultAmount = 100;
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
SaveConfig();
}
catch
{
PrintError("Error reading config, please check!");
Unsubscribe(nameof(OnActiveItemChanged));
Unsubscribe(nameof(OnPlayerInput));
}
}
protected override void LoadDefaultConfig()
{
_config = new Configuration();
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(_config);
#endregion
#region Data
private Dictionary<ulong, int> _data = new Dictionary<ulong, int>();
public static class Data
{
public static int Get(ulong userID)
{
if (_instance._data.ContainsKey(userID))
{
return _instance._data[userID];
}
return _instance._config.fertilizer.defaultAmount;
}
public static void Set(ulong userID, int amount)
{
_instance._data[userID] = amount;
Data.Save();
}
public static void Save()
{
Interface.Oxide.DataFileSystem.WriteObject(_instance.Name, _instance._data);
}
public static void Load()
{
try
{
_instance._data = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, int>>(_instance.Name);
}
catch (Exception e)
{
_instance.PrintError(e.Message);
_instance.Unsubscribe(nameof(OnActiveItemChanged));
_instance.Unsubscribe(nameof(OnPlayerInput));
}
}
}
#endregion
#region Language
private void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>()
{
{"notAllowed", "You are not allowed to use this command!"},
{"changeAmount", "The amount of fertilizer transferred has been changed to {0} pcs."},
{"currentAmount", "Current amount of fertilizer transferred: {0} pcs."}
}, this, "en");
lang.RegisterMessages(new Dictionary<string, string>()
{
{"notAllowed", "Вам не разрешено использование данной команды!" },
{"changeAmount", "Количество перекладываемого удобрения изменено на {0} шт." },
{"currentAmount", "Текущее количество перекладываемого удобрения: {0} шт." }
}, this, "ru");
lang.RegisterMessages(new Dictionary<string, string>()
{
{"notAllowed", "Вам не дозволено використання цієї команди!" },
{"changeAmount", "Кількість добрива, що перекладається, змінено на: {0} шт." },
{"currentAmount", "Поточна кількість добрива, що перекладається: {0} шт." }
}, this, "uk");
}
private string _(BasePlayer player, string key, params object[] args)
{
return string.Format(lang.GetMessage(key, this, player?.UserIDString), args);
}
#endregion
#region Oxide Hooks
private void Init()
{
permission.RegisterPermission(_config.autoGather, this);
permission.RegisterPermission(_config.autoCutting, this);
permission.RegisterPermission(_config.autoDying, this);
permission.RegisterPermission(_config.autoFertilizer, this);
checkSubscribeHooks();
}
private void Loaded()
{
_instance = this;
Data.Load();
}
[AutoPatch]
[HarmonyPatch(typeof(GrowableEntity), nameof(GrowableEntity.RPC_PickFruit))]
internal class GrowableEntity_RPC_PickFruit
{
static bool Prefix(GrowableEntity __instance, BaseEntity.RPCMessage msg)
{
if (_instance.checkPermission(msg.player, _instance._config.autoGather))
{
__instance.RPC_PickFruitAll(msg);
return false;
}
return true;
}
}
[AutoPatch]
[HarmonyPatch(typeof(GrowableEntity), nameof(GrowableEntity.RPC_TakeClone))]
internal class GrowableEntity_RPC_TakeClone
{
static bool Prefix(GrowableEntity __instance, BaseEntity.RPCMessage msg)
{
if (_instance.checkPermission(msg.player, _instance._config.autoCutting))
{
__instance.RPC_TakeCloneAll(msg);
return false;
}
return true;
}
}
[AutoPatch]
[HarmonyPatch(typeof(GrowableEntity), nameof(GrowableEntity.RPC_RemoveDying))]
internal class GrowableEntity_RPC_RemoveDying
{
static bool Prefix(GrowableEntity __instance, BaseEntity.RPCMessage msg)
{
if (_instance.checkPermission(msg.player, _instance._config.autoDying))
{
__instance.RPC_RemoveDyingAll(msg);
return false;
}
return true;
}
}
private void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem)
{
if (player == null)
return;
if (newItem != null && newItem.info.shortname == "fertilizer")
{
if (permission.UserHasPermission(player.UserIDString, _config.autoFertilizer))
{
_activeUse.Add(player.userID);
checkSubscribeHooks();
}
}
else
{
if (_activeUse.Contains(player.userID))
{
_activeUse.Remove(player.userID);
checkSubscribeHooks();
}
}
}
private void OnPlayerInput(BasePlayer player, InputState input)
{
if (_activeUse.Contains(player.userID) && input.WasJustReleased(BUTTON.FIRE_PRIMARY))
{
Item activeItem = player.GetActiveItem();
if (activeItem == null)
return;
if (activeItem.info.shortname != "fertilizer")
return;
PlanterBox planterBox;
if (IsLookingPlanterBox(player, out planterBox))
{
int amount = Data.Get(player.userID);
Item moveItem = (amount >= activeItem.amount) ? activeItem : activeItem.SplitItem(amount);
player.Command("note.inv", (object)moveItem.info.itemid, (object)-moveItem.amount);
EffectNetwork.Send(new Effect("assets/bundled/prefabs/fx/impacts/physics/phys-impact-meat-soft.prefab", player, 0, new Vector3(), new Vector3()), player.Connection);
if (!moveItem.MoveToContainer(planterBox.inventory, -1, true))
{
moveItem.Drop(player.GetDropPosition(), player.GetDropVelocity(), default(Quaternion));
}
}
}
}
#if DEBUG
private void OnHammerHit(BasePlayer player, HitInfo info)
{
if (player == null || info == null || info?.HitEntity == null)
return;
if (player.IsAdmin && player.serverInput.IsDown(BUTTON.FIRE_SECONDARY) && (info.HitEntity is PlanterBox))
{
(info.HitEntity as PlanterBox).DoSplash(ItemManager.FindItemDefinition("water"), 9000);
}
}
#endif
#endregion
#region Chat Command
[ChatCommand("fertilizer")]
private void fertilizer_command(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, _config.autoFertilizer))
{
SendReply(player, _(player, "notAllowed"));
return;
}
if (args.Length == 0)
{
SendReply(player, _(player, "currentAmount", Data.Get(player.userID)));
return;
}
int amount = _config.fertilizer.defaultAmount;
try
{
amount = Int32.Parse(args[0]);
}
catch { }
Data.Set(player.userID, amount);
SendReply(player, _(player, "changeAmount", amount));
}
#endregion
#region Helpers
public void checkSubscribeHooks()
{
if (_activeUse.Count > 0)
{
Subscribe(nameof(OnPlayerInput));
}
else
{
Unsubscribe(nameof(OnPlayerInput));
}
}
public bool checkPermission(BasePlayer player, string perm)
{
if (player == null || !permission.UserHasPermission(player.UserIDString, perm))
return false;
return player.serverInput.IsDown(BUTTON.SPRINT);
}
public bool IsLookingPlanterBox(BasePlayer player, out PlanterBox planterBox)
{
RaycastHit hit;
planterBox = null;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, _config.fertilizer.maxDistance, LayerMask.GetMask("Deployed")))
{
BaseEntity entity = hit.GetEntity();
if (entity is PlanterBox)
{
planterBox = entity as PlanterBox;
}
}
return planterBox != null;
}
#endregion
}
}