C#:
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<MapMarkerGenericRadius> MapMarkers = new List<MapMarkerGenericRadius>();
private List<OreResourceEntity> Nodes = new List<OreResourceEntity>();
private List<BaseAnimalNPC> Animals = new List<BaseAnimalNPC>();
private List<Item> Food = new List<Item>();
private List<CollectibleEntity> FoodEntities = new List<CollectibleEntity>();
private List<BasePlayer> LootingPlayers = new List<BasePlayer>();
private List<BasePlayer> CooldownPlayers = new List<BasePlayer>();
//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<string> permissions = new List<string>() { 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<BasePlayer>();
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<BasePlayer>();
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<LootContainer> lootContainers = new List<LootContainer>();
// List<CollectibleEntity> foodCollectible = new List<CollectibleEntity>();
//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<CollectibleEntity>()) {
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<Configuration>();
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<string, string>
{
["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
}
}