using Newtonsoft.Json; using System.Collections.Generic; using Oxide.Core.Libraries.Covalence; using UnityEngine; using System; //Add sufficient configuration for if and when markers are removed namespace Oxide.Plugins { [Info("Visibility", "Rustonauts", "1.2.6")] [Description("Marks various items on the map when the 'vi' command is used")] class Visibility : RustPlugin { #region Fields private const string genericPrefab = "assets/prefabs/tools/map/genericradiusmarker.prefab"; private const string visibilityMapMarker = "visibility.MapMarker"; private Configuration _config; private List MapMarkers = new List(); private List Nodes = new List(); private List Animals = new List(); private List Food = new List(); private List FoodEntities = new List(); private List LootingPlayers = new List(); private List CooldownPlayers = new List(); //permissions private const string perm_use = "visibility.use"; private const string perm_nodes = "visibility.nodes"; private const string perm_animals = "visibility.animals"; private const string perm_food = "visibility.food"; private List permissions = new List() { perm_use, perm_nodes, perm_animals, perm_food }; #endregion #region Hooks object CanNetworkTo(MapMarkerGenericRadius radius, BasePlayer target) { if (radius.name == visibilityMapMarker) { if(target.userID != radius.OwnerID) { //Puts("-- NO MATCH"); // Puts("-- target: {0}", target.UserIDString); // Puts("-- radius: {0}", radius.OwnerID.ToString()); return false; } else { //Puts("-- MATCH"); // Puts("-- target: {0}", target.UserIDString); // Puts("-- radius: {0}", radius.OwnerID.ToString()); return null; } } return null; } private void OnUserConnected(IPlayer player) { if(_config.announce_connection) PrintToChat(player.Name + " has connected."); } void OnLootEntity(BasePlayer player, BaseEntity entity) { LootingPlayers.Add(player); } void OnPlayerLootEnd(PlayerLoot inventory) { BasePlayer _player = inventory.GetComponent(); LootingPlayers.Remove(_player); } object OnLootSpawn(LootContainer container) { foreach(Item item in container.inventory.itemList) { if(item.info.category.ToString() == "Food") AddFoodItem(item); } return null; } private void OnCollectiblePickup(CollectibleEntity entity, BasePlayer player) { RemoveFoodEntity(entity); } void OnEntitySpawned(BaseNetworkable entity) { //whenever an entity spawns, if it's an ore resource entity, add it to the NodeMarkers List if(entity is OreResourceEntity) AddNode(entity); if(entity is BaseAnimalNPC) AddAnimal(entity); if(entity is CollectibleEntity) { CollectibleEntity foodEntity = entity as CollectibleEntity; if(foodEntity != null) { //iterate through all items in each collectible entity foreach(ItemAmount item in foodEntity.itemList) { if(item.itemDef.category == ItemCategory.Food) AddFoodEntity(foodEntity); } } } } void OnEntityKill(BaseNetworkable entity) { if(entity is OreResourceEntity) RemoveNode(entity); if(entity is BaseAnimalNPC) RemoveAnimal(entity); } object CanMoveItem(Item item, PlayerInventory playerLoot, uint targetContainer, int targetSlot, int amount) { if(item.info.category.ToString() == "Food"){ BasePlayer _player = playerLoot.loot.GetComponent(); if(IsLooting(_player)) RemoveFoodItem(item); } return null; } // || item.info.shortname == "berry-black-collectable.prefab" || item.info.shortname == "berry-blue-collectable.prefab" || item.info.shortname == "berry-green-collectable.prefab " // || item.info.shortname == "granolabar.item.prefab" || item.info.shortname == "berry-black-collectable.prefab" || item.info.shortname == "berry-blue-collectable.prefab #endregion #region Init // Called when the plugin is initializing void Init() { RegisterPermissions(); // Register the chat command AddCovalenceCommand("vi", nameof(Visualize)); InitNodes(); InitAnimals(); InitFood(); } #endregion #region Core // Handles the chat command void Visualize(IPlayer iplayer, string command, string[] args) { BasePlayer player = iplayer.Object as BasePlayer; if(!IsCooldown(player)) { if (player == null) return; if (!HasPerm(player.UserIDString, perm_use)) { ChatMessage(iplayer, "NoPerms"); return; } if (args.Length < 1) { //player.ChatMessage(local.GetMessage("mlockUsage",player.userID)); } else if(args.Length == 1) { if(args[0] == "nodes") { if (!HasPerm(player.UserIDString, perm_nodes)) { ChatMessage(iplayer, "NoPermsNodes"); return; } if(_config.allow_nodes) LoadMarkers("nodes", player); } else if(args[0] == "animals") { if (!HasPerm(player.UserIDString, perm_animals)) { ChatMessage(iplayer, "NoPermsAnimals"); return; } if(_config.allow_animals) LoadMarkers("animals", player); } else if(args[0] == "food") { if (!HasPerm(player.UserIDString, perm_food)) { ChatMessage(iplayer, "NoPermsFood"); return; } if(_config.allow_food) LoadMarkers("food", player); } else if(args[0] == "clear") { RemoveMarkers(true); } timer.Once(_config.vi_time, () => RemoveMarkers()); //create usage cooldown CooldownPlayers.Add(player); timer.Once(_config.vi_cooldown, () => EndCooldown(player)); } return; } ChatMessage(iplayer, "Cooldown"); } private void EndCooldown(BasePlayer player) { CooldownPlayers.Remove(player); } #endregion #region Helpers private bool IsLooting(BasePlayer player) { foreach(BasePlayer _player in LootingPlayers) { if(_player.userID == player.userID) return true; } return false; } private bool IsCooldown(BasePlayer player) { foreach(BasePlayer _player in CooldownPlayers) { if(_player.userID == player.userID) return true; } return false; } private void ChatMessage(IPlayer player, string langKey, params object[] args) { if (player.IsConnected) player.Message(GetLang(langKey, player.Id, args)); } private bool HasPerm(string playerId, string perm) => permission.UserHasPermission(playerId, perm); private string GetLang(string langKey, string playerId = null, params object[] args) { return string.Format(lang.GetMessage(langKey, this, playerId), args); } private void RegisterPermissions() { foreach (string perm in permissions) permission.RegisterPermission(perm, this); } private void InitAnimals() { Animals.Clear(); foreach(var entity in BaseNetworkable.serverEntities) { if(entity is BaseAnimalNPC) { var animal = (entity as BaseAnimalNPC); Animals.Add(animal); } } Puts(GetLang("InitAnimals")); return; } private void InitNodes() { Nodes.Clear(); foreach(var entity in BaseNetworkable.serverEntities) { if(entity is OreResourceEntity) { var ore = (entity as OreResourceEntity); Nodes.Add(ore); } } Puts(GetLang("InitNodes")); return; } private void InitFood() { List lootContainers = new List(); // List foodCollectible = new List(); //get all loot containers foreach(var entity in BaseNetworkable.serverEntities) { if(entity is LootContainer) lootContainers.Add((LootContainer)entity); } //get all collectible entities foreach (var entity in UnityEngine.Object.FindObjectsOfType()) { if(entity is CollectibleEntity) { //iterate through all items in each collectible entity foreach(ItemAmount item in entity.itemList) { if(item.itemDef.category == ItemCategory.Food) FoodEntities.Add(entity); } } } //iterate through all items in each container foreach(var container in lootContainers) { foreach(Item item in container.inventory.itemList) { if(item.info.category.ToString() == "Food") Food.Add(item); } } Puts(GetLang("InitFood")); return; } private void RemoveNode(BaseNetworkable entity) { var ore = (entity as OreResourceEntity); if(Nodes.Contains(ore)) Nodes.Remove(ore); return; } private void RemoveAnimal(BaseNetworkable entity) { var animal = (entity as BaseAnimalNPC); if(Animals.Contains(animal)) Animals.Remove(animal); return; } private void RemoveFoodItem(Item item) { if(Food.Contains(item)) Food.Remove(item); return; } private void RemoveFoodEntity(CollectibleEntity entity) { if(FoodEntities.Contains(entity)) FoodEntities.Remove(entity); return; } private void AddNode(BaseNetworkable entity) { var ore = (entity as OreResourceEntity); if(!Nodes.Contains(ore)) Nodes.Add(ore); return; } private void AddAnimal(BaseNetworkable entity) { var animal = (entity as BaseAnimalNPC); if(!Animals.Contains(animal)) Animals.Add(animal); return; } private void AddFoodItem(Item item) { if(!Food.Contains(item)) Food.Add(item); return; } private void AddFoodEntity(CollectibleEntity entity) { if(!FoodEntities.Contains(entity)) FoodEntities.Add(entity); return; } private void AddItemMarker(BasePlayer _player, Item item=null) { if(item != null) { if(item.parent != null) { var pos = item.parent.dropPosition; if(pos != Vector3.zero) { MapMarkerGenericRadius mapMarker = GameManager.server.CreateEntity(genericPrefab, pos) as MapMarkerGenericRadius; mapMarker.alpha = 1; mapMarker.name = visibilityMapMarker; mapMarker.OwnerID = _player.userID; //mapMarker.OwnerID = 76561199470510455; mapMarker.color1 = Color.green; mapMarker.color2 = Color.green; mapMarker.radius = 0.02f; if(!MapMarkers.Contains(mapMarker)) { MapMarkers.Add(mapMarker); mapMarker.Spawn(); mapMarker.SendUpdate(); } } } } return; } private void AddCollectibleMarker(CollectibleEntity entity, BasePlayer _player) { //create new Map Marker var pos = entity.transform.position; MapMarkerGenericRadius mapMarker = GameManager.server.CreateEntity(genericPrefab, pos) as MapMarkerGenericRadius; mapMarker.alpha = 1; mapMarker.name = visibilityMapMarker; mapMarker.OwnerID = _player.userID; //mapMarker.OwnerID = 76561199470510455; //iterate through all items in each collectible entity foreach(ItemAmount item in entity.itemList) { if(item.itemDef.category == ItemCategory.Food) { mapMarker.color1 = Color.cyan; mapMarker.color2 = Color.cyan; mapMarker.radius = 0.02f; break; } } MapMarkers.Add(mapMarker); mapMarker.Spawn(); mapMarker.SendUpdate(); return; } private void AddMarker(BaseEntity entity, BasePlayer _player, string _name) { //create new Map Marker var pos = entity.transform.position; MapMarkerGenericRadius mapMarker = GameManager.server.CreateEntity(genericPrefab, pos) as MapMarkerGenericRadius; //MapMarkerGenericRadius mapMarker = GameManager.server.CreateEntity("assets/prefabs/tools/map/ui/ui.map.teamposition.prefab", pos) as MapMarkerGenericRadius; mapMarker.alpha = 1; mapMarker.name = visibilityMapMarker; mapMarker.OwnerID = _player.userID; //mapMarker.OwnerID = 76561199470510455; //determining and setting the color based on the ore type if(entity.ShortPrefabName.Contains("sulfur-ore")) { mapMarker.color1 = Color.yellow; mapMarker.color2 = Color.yellow; mapMarker.radius = 0.02f; } else if(entity.ShortPrefabName.Contains("metal-ore")) { mapMarker.color1 = Color.red; mapMarker.color2 = Color.red; mapMarker.radius = 0.02f; } else if(entity.ShortPrefabName.Contains("stone-ore")) { mapMarker.color1 = Color.black; mapMarker.color2 = Color.black; mapMarker.radius = 0.02f; } else if (entity.ShortPrefabName.Contains("bear")) { mapMarker.color1 = Color.black; mapMarker.color2 = Color.black; mapMarker.radius = 0.05f; } else if (entity.ShortPrefabName.Contains("boar")) { mapMarker.color1 = Color.red; mapMarker.color2 = Color.red; mapMarker.radius = 0.03f; } else if (entity.ShortPrefabName.Contains("wolf")) { mapMarker.color1 = Color.yellow; mapMarker.color2 = Color.yellow; mapMarker.radius = 0.02f; } else if (entity.ShortPrefabName.Contains("stag")) { mapMarker.color1 = Color.cyan; mapMarker.color2 = Color.cyan; mapMarker.radius = 0.02f; } MapMarkers.Add(mapMarker); mapMarker.Spawn(); mapMarker.SendUpdate(); return; } private void LoadMarkers(string resource, BasePlayer _player) { if(resource == "nodes") { // interate through all the nodes in the Nodes List and spawn them on the map var i=0; foreach (OreResourceEntity ore in Nodes) { if (ore != null) { i++; AddMarker(ore, _player, "ore"+i); } } } else if(resource == "animals") { var i=0; foreach(BaseAnimalNPC animal in Animals) { if(animal != null) { i++; AddMarker(animal, _player, "animal"+i); } } } else if(resource == "food") { //goes through all the food items that are of type Item (within loot containers) foreach(Item item in Food) { if(item != null) { AddItemMarker(_player, item); } } //goes through all the food items that are of type entity (collectibles on the ground) foreach(var entity in FoodEntities) { if(entity != null) AddCollectibleMarker(entity, _player); } } return; } private void RemoveNodes() { foreach(OreResourceEntity ore in Nodes) { if(ore != null) Nodes.Remove(ore); } return; } private void RemoveAnimals() { foreach(BaseAnimalNPC animal in Animals) { if(animal != null) Animals.Remove(animal); } return; } private void RemoveFood() { foreach(Item item in Food) { if(item != null) Food.Remove(item); } foreach(CollectibleEntity entity in FoodEntities) { if(entity != null) FoodEntities.Remove(entity); } return; } private void RemoveMarkers(bool all=false) { foreach (var marker in MapMarkers) { if (marker != null) { marker.Kill(); marker.SendUpdate(); } } if(all) { foreach (var entity in BaseNetworkable.serverEntities) { if(entity is MapMarkerGenericRadius) { var mapMarker = (entity as MapMarkerGenericRadius); mapMarker.Kill(); mapMarker.SendUpdate(); } } } MapMarkers.Clear(); return; } #endregion #region Configuration protected override void LoadConfig() { base.LoadConfig(); try { _config = Config.ReadObject(); if (_config == null) throw new Exception(); Puts("Config loaded"); } catch { Puts("config error, create defaults"); LoadDefaultConfig(); } //if(!IsConfigCompatible()) LoadDefaultConfig(); } protected override void LoadDefaultConfig() { _config = new Configuration(); SaveConfig(); } protected override void SaveConfig() { Config.WriteObject(_config, true); } private class Configuration { [JsonProperty(PropertyName = "Visibility time (seconds):")] public int vi_time { get; set; } = 8; [JsonProperty(PropertyName = "Visibility cooldown (seconds):")] public int vi_cooldown { get; set; } = 60; [JsonProperty(PropertyName = "Allow Nodes Visibility:")] public bool allow_nodes { get; set; } = true; [JsonProperty(PropertyName = "Allow Animals Visibility:")] public bool allow_animals { get; set; } = true; [JsonProperty(PropertyName = "Allow Food Visibility:")] public bool allow_food { get; set; } = true; [JsonProperty(PropertyName = "Announce Player Connection")] public bool announce_connection { get; set; } = true; } #endregion #region Localization protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["InitNodes"] = "-- gathered nodes --", ["InitAnimals"] = "-- spotted animals --", ["InitFood"] = "-- visualized food --", ["NoPerms"] = "You don't have permissions to use this command", ["NoPermsNodes"] = "You don't have permissions to use this command for nodes", ["NoPermsAnimals"] = "You don't have permissions to use this command for animals", ["NoPermsFood"] = "You don't have permissions to use this command for food", ["Cooldown"] = "Sorry, you are in a cooldown period and cannot use Visibility at this moment." }, this); } #endregion Localization } }