using System; using System.Collections.Generic; using System.Linq; using System.Text; using Oxide.Core; using Oxide.Core.Libraries.Covalence; using UnityEngine; namespace Oxide.Plugins { [Info("Farm Tools", "Clearshot", "1.2.2")] [Description("Farming made easy. Take control of farming with binds.")] class FarmTools : CovalencePlugin { private PluginConfig _config; private Game.Rust.Libraries.Player _rustPlayer = Interface.Oxide.GetLibrary("Player"); private List _usedCommand = new List(); private Dictionary _cooldown = new Dictionary(); private int _debrisLayerMask = LayerMask.GetMask("Debris"); private int _deployedLayerMask = LayerMask.GetMask("Deployed"); private const string PERM_CLONE = "farmtools.clone"; private const string PERM_CLONE_ALL = "farmtools.clone.all"; private const string PERM_HARVEST_ALL = "farmtools.harvest.all"; private const string PERM_PLANT_ALL = "farmtools.plant.all"; private const string PERM_GENES = "farmtools.genes"; private void SendChatMsg(BasePlayer pl, string msg, string prefix = null) => _rustPlayer.Message(pl, msg, prefix != null ? prefix : lang.GetMessage("ChatPrefix", this, pl.UserIDString), Convert.ToUInt64(_config.chatIconID), Array.Empty()); private void Init() { permission.RegisterPermission(PERM_CLONE, this); permission.RegisterPermission(PERM_CLONE_ALL, this); permission.RegisterPermission(PERM_HARVEST_ALL, this); permission.RegisterPermission(PERM_PLANT_ALL, this); permission.RegisterPermission(PERM_GENES, this); } private void ShowHelp(BasePlayer pl) { StringBuilder sb = new StringBuilder(); sb.AppendLine(lang.GetMessage("HelpTitle", this, pl.UserIDString)); sb.AppendLine(lang.GetMessage("Help", this, pl.UserIDString)); sb.AppendLine(lang.GetMessage("HelpClone", this, pl.UserIDString)); if (permission.UserHasPermission(pl.UserIDString, PERM_CLONE_ALL)) sb.AppendLine(lang.GetMessage("HelpCloneAll", this, pl.UserIDString)); if (permission.UserHasPermission(pl.UserIDString, PERM_HARVEST_ALL)) sb.AppendLine(lang.GetMessage("HelpHarvestAll", this, pl.UserIDString)); if (permission.UserHasPermission(pl.UserIDString, PERM_PLANT_ALL)) sb.AppendLine(lang.GetMessage("HelpPlantAll", this, pl.UserIDString)); if (permission.UserHasPermission(pl.UserIDString, PERM_GENES)) sb.AppendLine(lang.GetMessage("HelpGenes", this, pl.UserIDString)); SendChatMsg(pl, sb.ToString(), ""); } #region Commands [Command("farmtools")] private void FarmToolsCommand(IPlayer player, string command, string[] args) { if (player.IsServer) return; BasePlayer pl = player.Object as BasePlayer; if (pl == null) return; ShowHelp(pl); } [Command("farmtools.clone", "clone")] private void CloneCommand(IPlayer player, string command, string[] args) { if (player.IsServer) return; BasePlayer pl = player.Object as BasePlayer; if (pl == null) return; if (!player.HasPermission(PERM_CLONE)) { SendChatMsg(pl, string.Format(lang.GetMessage("NoPerms", this, pl.UserIDString), command)); return; } if (!_usedCommand.Contains(pl.userID)) _usedCommand.Add(pl.userID); RaycastHit hit; if (Physics.Raycast(pl.eyes.HeadRay(), out hit, 4f)) { Collider[] hitColliders = new Collider[5]; int numColliders = Physics.OverlapSphereNonAlloc(hit.point, 0.65f, hitColliders, _debrisLayerMask); for (int i = 0; i < numColliders; i++) { GrowableEntity growableEntity = hitColliders[i]?.gameObject?.GetComponent(); if (growableEntity != null) { growableEntity.TakeClones(pl); break; } } } } [Command("farmtools.cloneall", "cloneall")] private void CloneAllCommand(IPlayer player, string command, string[] args) { if (player.IsServer) return; BasePlayer pl = player.Object as BasePlayer; if (pl == null) return; if (!player.HasPermission(PERM_CLONE_ALL)) { SendChatMsg(pl, string.Format(lang.GetMessage("NoPerms", this, pl.UserIDString), command)); return; } if (!_usedCommand.Contains(pl.userID)) _usedCommand.Add(pl.userID); PlanterBox planter = EyeTraceToEntity(pl, 4f, _deployedLayerMask) as PlanterBox; if (planter == null) return; foreach (BaseEntity baseEntity in planter.children.ToList()) { if (baseEntity == null) continue; GrowableEntity growableEntity = baseEntity as GrowableEntity; if (growableEntity == null) continue; growableEntity.TakeClones(pl); } } [Command("farmtools.harvestall", "harvestall")] private void HarvestAllCommand(IPlayer player, string command, string[] args) { if (player.IsServer) return; BasePlayer pl = player.Object as BasePlayer; if (pl == null) return; if (!player.HasPermission(PERM_HARVEST_ALL)) { SendChatMsg(pl, string.Format(lang.GetMessage("NoPerms", this, pl.UserIDString), command)); return; } if (!_usedCommand.Contains(pl.userID)) _usedCommand.Add(pl.userID); PlanterBox planter = EyeTraceToEntity(pl, 4f, _deployedLayerMask) as PlanterBox; if (planter == null) return; foreach (BaseEntity baseEntity in planter.children.ToList()) { if (baseEntity == null) continue; GrowableEntity growableEntity = baseEntity as GrowableEntity; if (growableEntity == null) continue; if (growableEntity.State == PlantProperties.State.Dying) growableEntity.RemoveDying(pl); else growableEntity.PickFruit(pl); } } [Command("farmtools.plantall", "plantall")] private void PlantAllCommand(IPlayer player, string command, string[] args) { if (player.IsServer) return; BasePlayer pl = player.Object as BasePlayer; if (pl == null) return; if (!player.HasPermission(PERM_PLANT_ALL)) { SendChatMsg(pl, string.Format(lang.GetMessage("NoPerms", this, pl.UserIDString), command)); return; } if (!_usedCommand.Contains(pl.userID)) _usedCommand.Add(pl.userID); Planner planner = pl.GetHeldEntity() as Planner; if (planner == null) return; PlanterBox planter = EyeTraceToEntity(pl, 4f, _deployedLayerMask) as PlanterBox; if (planter == null) return; /**************************************************************************** * * * Credits to: Auto Plant by rostov114 (https://umod.org/plugins/auto-plant) * * * ****************************************************************************/ Construction construction = PrefabAttribute.server.Find(planner.GetDeployable().prefabID); List targets = Facepunch.Pool.GetList(); foreach (Socket_Base socket in PrefabAttribute.server.FindAll(planter.prefabID).Where(x => x.female)) { Vector3 pos = planter.transform.TransformPoint(socket.worldPosition); Construction.Target target = new Construction.Target(); target.entity = planter; target.ray = new Ray(pos + Vector3.up * 1.0f, Vector3.down); target.onTerrain = false; target.position = pos; target.normal = Vector3.up; target.rotation = new Vector3(); target.player = pl; target.valid = true; target.socket = socket; target.inBuildingPrivilege = true; Socket_Base maleSocket = construction.allSockets.Where(x => x.male).FirstOrDefault(); if (maleSocket != null && !maleSocket.CheckSocketMods(maleSocket.DoPlacement(target))) continue; targets.Add(target); } foreach (Construction.Target target in targets) { planner.DoBuild(target, construction); } Facepunch.Pool.FreeList(ref targets); // end credits } [Command("farmtools.genes", "genes")] private void GenesCommand(IPlayer player, string command, string[] args) { if (player.IsServer) return; BasePlayer pl = player.Object as BasePlayer; if (pl == null) return; if (!player.HasPermission(PERM_GENES)) { SendChatMsg(pl, string.Format(lang.GetMessage("NoPerms", this, pl.UserIDString), command)); return; } if (IsPlayerOnCooldown(pl)) return; if (!_usedCommand.Contains(pl.userID)) _usedCommand.Add(pl.userID); BaseEntity entity = EyeTraceToEntity(pl, 4f, _deployedLayerMask); PlanterBox planter = entity as PlanterBox; if (planter != null) { Dictionary> genes = new Dictionary>(); foreach (BaseEntity baseEntity in planter.children.ToList()) { if (baseEntity == null) continue; GrowableEntity growableEntity = baseEntity as GrowableEntity; if (growableEntity == null || growableEntity.State == PlantProperties.State.Dying) continue; string g = ""; string itemName = growableEntity.SourceItemDef.displayName.english; if (!genes.ContainsKey(itemName)) { genes.Add(itemName, new List()); } foreach (GrowableGene gene in growableEntity.Genes.Genes) { g += gene.GetDisplayCharacter(); } if (!genes[itemName].Contains(g)) { genes[itemName].Add(g); } } GiveGenesNote(pl, genes, lang.GetMessage("PlanterGenes", this, pl.UserIDString)); return; } StorageContainer container = entity as StorageContainer; if (container != null) { Dictionary> genes = new Dictionary>(); foreach (Item i in container.inventory.itemList) { if (i.info.amountType != ItemDefinition.AmountType.Genetics || i?.instanceData?.dataInt == null) continue; string g = ""; string itemName = i.info.displayName.english; if (!genes.ContainsKey(itemName)) { genes.Add(itemName, new List()); } GrowableGenes growGenes = new GrowableGenes(); GrowableGeneEncoding.DecodeIntToGenes(i.instanceData.dataInt, growGenes); foreach (GrowableGene gene in growGenes.Genes) { g += gene.GetDisplayCharacter(); } if (!genes[itemName].Contains(g)) { genes[itemName].Add(g); } } GiveGenesNote(pl, genes, lang.GetMessage("ContainerGenes", this, pl.UserIDString)); return; } SendChatMsg(pl, lang.GetMessage("InvalidGeneEntity", this, pl.UserIDString)); } #endregion #region Hooks private void OnUserDisconnected(IPlayer player) { BasePlayer pl = player.Object as BasePlayer; if (pl == null) return; _usedCommand.Remove(pl.userID); _cooldown.Remove(pl.userID); } private void CanTakeCutting(BasePlayer pl, GrowableEntity plant) { if (permission.UserHasPermission(pl.UserIDString, PERM_CLONE) || permission.UserHasPermission(pl.UserIDString, PERM_CLONE_ALL)) { if (!_usedCommand.Contains(pl.userID)) { ShowHelp(pl); _usedCommand.Add(pl.userID); } } } #endregion #region Helpers public bool IsPlayerOnCooldown(BasePlayer pl) { if (_cooldown.ContainsKey(pl.userID) && Time.realtimeSinceStartup < _cooldown[pl.userID]) { SendChatMsg(pl, string.Format(lang.GetMessage("CommandCooldown", this, pl.UserIDString), Math.Ceiling(_cooldown[pl.userID] - Time.realtimeSinceStartup))); return true; } return false; } private void GiveGenesNote(BasePlayer pl, Dictionary> genes, string title) { if (genes.Count < 1) { SendChatMsg(pl, lang.GetMessage("InvalidGeneEntity", this, pl.UserIDString)); return; } Item item = ItemManager.CreateByName("note"); item.text = $"{title}\n\n"; foreach (KeyValuePair> i in genes) { item.text += i.Key + "\n"; foreach (string gene in i.Value) { item.text += gene + "\n"; } item.text += "\n"; } if (_config.printGenesToConsole) pl.ConsoleMessage(item.text); pl.GiveItem(item, BaseEntity.GiveItemReason.PickedUp); SendChatMsg(pl, lang.GetMessage("GeneNote", this, pl.UserIDString)); _cooldown[pl.userID] = Time.realtimeSinceStartup + _config.geneCooldown; } private BaseEntity EyeTraceToEntity(BasePlayer pl, float distance, int mask = ~0) { RaycastHit hit; return Physics.Raycast(pl.eyes.HeadRay(), out hit, distance, mask) ? hit.GetEntity() : null; } #endregion #region Config protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["ChatPrefix"] = $"[{Title}]", ["NoPerms"] = "You do not have permission to use {0}!", ["HelpTitle"] = $"{Title} Help\n", ["Help"] = "Bind a key to a FarmTools command using the F1 console\n", ["HelpClone"] = "Take clone from a single plant\nbind farmtools.clone\nchat command: /clone", ["HelpCloneAll"] = "\nTake all clones from a planter\nbind farmtools.cloneall\nchat command: /cloneall", ["HelpHarvestAll"] = "\nHarvest all plants or remove dying plants from a planter\nbind farmtools.harvestall\nchat command: /harvestall", ["HelpPlantAll"] = "\nPlant all seeds in the target planter\nbind farmtools.plantall\nchat command: /plantall", ["HelpGenes"] = "\nCopy genes from a planter box or storage container\nbind farmtools.genes\nchat command: /genes", ["PlanterGenes"] = "][ Planter Genes ][", ["ContainerGenes"] = "][ Container Genes ][", ["GeneNote"] = "A note with genes has been added to your inventory.\n\nGenes can also be copied from the F1 console with console.copy.", ["InvalidGeneEntity"] = "Unable to find genes! Look at a Planter Box or Storage Container and try again.", ["CommandCooldown"] = "Please wait {0}s!" }, this); } protected override void LoadDefaultConfig() { Config.WriteObject(GetDefaultConfig(), true); } private PluginConfig GetDefaultConfig() { return new PluginConfig(); } protected override void LoadConfig() { base.LoadConfig(); _config = Config.ReadObject(); Config.WriteObject(_config, true); } private class PluginConfig { public string chatIconID = "0"; public bool printGenesToConsole = true; public float geneCooldown = 10; } #endregion } }