C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*
NPCVendingMapMarker - A Rust umod plugin to add in-game vending map markers to NPC's.Copyright (C) 2020 by Pinguin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.You should have received a copy of the GNU General Public License
along with this program.If not, see <https://www.gnu.org/licenses/>.*/
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
namespace Oxide.Plugins
{
[Info("NPC Vending Map Marker", "PinguinNordpol", "0.1.0")]
[Description("Adds in-game vending map markers to NPC's")]
class NPCVendingMapMarker : CovalencePlugin
{
#region Fields
[PluginReference]
private Plugin HumanNPC;
// Configuration data
private NPCVendingMapMarkerConfig config_data;
// List of currently spawned vending map markers
private Dictionary<ulong, VendingMachineMapMarker> map_markers = new Dictionary<ulong, VendingMachineMapMarker>();
// Structure to hold temporary config values while adding a new vending map marker
private struct TempVmm
{
public ulong request_uid;
public string shop_name;
}
// List of current temporary vending map markers values
private List<TempVmm> TempVmms = new List<TempVmm>();
#endregion
#region Plugin Config
/*
* Classes & functions to load / store plugin configuration
*/
private class MarkerData
{
public string shop_name;
public UnityEngine.Vector3 position;
/*
* Constructor
*/
public MarkerData(string _shop_name, UnityEngine.Vector3 _position)
{
this.shop_name = _shop_name;
this.position = _position;
}
}
private class NPCVendingMapMarkerConfig
{
public Dictionary<ulong, MarkerData> configured_markers = new Dictionary<ulong, MarkerData>();
public string currency_sign = "RP";
public bool debug = false;
}
protected override void LoadDefaultConfig()
{
Config.WriteObject(GetDefaultConfig(), true);
}
private NPCVendingMapMarkerConfig GetDefaultConfig()
{
return new NPCVendingMapMarkerConfig();
}
#endregion
#region ServerRewards structures / functions
private class SR_NPCData
{
public Dictionary<string, SR_NPCInfo> npcInfo = new Dictionary<string, SR_NPCInfo>();
public class SR_NPCInfo
{
public string name;
public float x, z;
public bool useCustom, sellItems, sellKits, sellCommands, canTransfer, canSell, canExchange;
public List<string> items = new List<string>();
public List<string> kits = new List<string>();
public List<string> commands = new List<string>();
}
}
private class SR_RewardData
{
public Dictionary<string, SR_RewardItem> items = new Dictionary<string, SR_RewardItem>();
public SortedDictionary<string, SR_RewardKit> kits = new SortedDictionary<string, SR_RewardKit>();
public SortedDictionary<string, SR_RewardCommand> commands = new SortedDictionary<string, SR_RewardCommand>();
public class SR_RewardItem : SR_Reward
{
public string shortname, customIcon;
public int amount;
public ulong skinId;
public bool isBp;
public SR_Category category;
}
public enum SR_Category { None, Weapon, Construction, Items, Resources, Attire, Tool, Medical, Food, Ammunition, Traps, Misc, Component, Electrical, Fun }
public class SR_RewardKit : SR_Reward
{
public string kitName, description, iconName;
}
public class SR_RewardCommand : SR_Reward
{
public string description, iconName;
public List<string> commands = new List<string>();
}
public class SR_Reward
{
public string displayName;
public int cost;
public int cooldown;
}
}
// ServerRewards data
private SR_NPCData sr_npcdata;
private SR_RewardData sr_rewarddata;
private bool sr_enabled = false;
/*
* Try to read ServerRewards data files
*/
private void ReadServerRewardsData()
{
bool flag = true;
DynamicConfigFile npc_data, reward_data;
// Load data files
this.LogDebug("Trying to read ServerRewards plugin data files");
if (!Interface.Oxide.DataFileSystem.ExistsDatafile("ServerRewards/npc_data") || !Interface.Oxide.DataFileSystem.ExistsDatafile("ServerRewards/reward_data"))
{
// If data files do not exist, do not try to load them to prevent creating empty files
this.sr_enabled = false;
return;
}
npc_data = Interface.Oxide.DataFileSystem.GetFile("ServerRewards/npc_data");
reward_data = Interface.Oxide.DataFileSystem.GetFile("ServerRewards/reward_data");
// Try parsing the data files
try
{
this.sr_rewarddata = reward_data.ReadObject<SR_RewardData>();
this.LogDebug(string.Format("Successfully read {0} ServerRewards reward entrie(s)", this.sr_rewarddata.items.Count));
}
catch
{
this.LogDebug("No ServerRewards reward data found");
this.sr_rewarddata = new SR_RewardData();
flag = false;
}
try
{
this.sr_npcdata = npc_data.ReadObject<SR_NPCData>();
this.LogDebug(string.Format("Successfully read {0} ServerRewards NPC entrie(s)", this.sr_npcdata.npcInfo.Count));
}
catch
{
this.LogDebug("No ServerRewards npc data found");
this.sr_npcdata = new SR_NPCData();
flag = false;
}
this.sr_enabled = flag;
}
/*
*
*/
private string GetServerRewardsData(string _npc_id)
{
string ret = "";
// Make sure we ServerRewards data files were loaded
if (!this.sr_enabled) return "";
// Check if the given NPC has a shop configured
this.LogDebug("Checking ServerRewards data for shop items to display");
if (!this.sr_npcdata.npcInfo.ContainsKey(_npc_id)) return "";
// Check if shop has items to sell
if (this.sr_npcdata.npcInfo[_npc_id].items.Count == 0) return "";
// Parse and add items
this.LogDebug("ServerRewards has shop items to display for current NPC");
foreach (string reward_item in this.sr_npcdata.npcInfo[_npc_id].items)
{
if (this.sr_rewarddata.items.ContainsKey(reward_item))
{
this.LogDebug(string.Format("Found values for item '{0}'.Adding", reward_item));
ret += string.Format("\r\n{0} {1} | {2} {3}", this.sr_rewarddata.items[reward_item].amount, this.sr_rewarddata.items[reward_item].displayName, this.sr_rewarddata.items[reward_item].cost, this.config_data.currency_sign);
}
else
{
this.LogDebug(string.Format("Did not find values for item '{0}'", reward_item));
}
}
if (ret != "") ret = "\r\n" + ret;
return ret;
}
#endregion
#region Umod Hooks
/*
* Initialize plugin once loaded
*/
void Loaded()
{
if (this.HumanNPC == null)
{
// Can't do much without HumanNPC
LogWarning("This plugin requires the HumanNPC plugin in order to be of any use!");
}
// Unsubscribe from OnUseNPC until we actually need it
Unsubscribe("OnUseNPC");
// Try reading ServerRewards plugin data
this.ReadServerRewardsData();
}
/*
* Remove all vending map markers on unload
*/
void Unload()
{
this.ClearVendingMapMarkers();
}
/*
* Load plugin config as soon as possible
*/
void Init()
{
// Load plugin config
this.config_data = Config.ReadObject<NPCVendingMapMarkerConfig>();
}
#endregion
#region HumanNPC Hooks
/*
* Add vending map marker when configured NPCs respawn
*/
void OnNPCRespawn(BasePlayer npc)
{
// If new NPC has a vending map marker configured, display it
foreach(KeyValuePair<ulong, MarkerData> cm in this.config_data.configured_markers)
{
if(cm.Key == npc.userID)
{
this.AddMapMarker(cm.Key, cm.Value);
break;
}
}
}
/*
* Remove vending map marker when configured NPCs die
*/
void OnKillNPC(BasePlayer npc, HitInfo hitinfo)
{
// If NPC had a vending map marker, remove it
Dictionary<ulong, MarkerData>.KeyCollection keys = this.config_data.configured_markers.Keys;
foreach (ulong key in keys.ToList())
{
if(key == npc.userID)
{
this.RemoveMapMarker(key);
break;
}
}
}
/*
* Add vending map marker to NPC
*/
void OnUseNPC(BasePlayer npc, BasePlayer player)
{
// Check if we have a temporary configuration from current player
this.LogDebug(string.Format("Looping over {0} temp_vmms", this.TempVmms.Count));
for(int i = 0; i < this.TempVmms.Count; i++)
{
if(this.TempVmms[i].request_uid == player.userID) {
// Found a temporary configuration, let's finish it
this.LogDebug(string.Format("Found temp_vmm for user id {0}", player.userID));
// Make sure selected NPC is unconfigured
if (this.map_markers.ContainsKey(npc.userID)) {
this.ReplyToPlayer(player.IPlayer, string.Format(lang.GetMessage("NpcAlreadyHasMapMarker", this, player.IPlayer.Id), npc.userID));
return;
}
// Try to re-read ServerRewards data files
this.ReadServerRewardsData();
// Create new vending map marker for NPC and display it
this.LogDebug(string.Format("Creating new npcvmm for npc id {0} with name '{1}' at position {2}", npc.userID, this.TempVmms[i].shop_name, npc.transform.position.ToString()));
MarkerData marker_data = new MarkerData(this.TempVmms[i].shop_name, npc.transform.position);
if(!this.AddMapMarker(npc.userID, marker_data))
{
this.ReplyToPlayer(player.IPlayer, string.Format(lang.GetMessage("FailedSpawningMarker", this, player.IPlayer.Id)));
return;
}
// Add marker permanently to config
this.config_data.configured_markers.Add(npc.userID, marker_data);
Config.WriteObject<NPCVendingMapMarkerConfig>(this.config_data, true);
// Remove temporary config values
this.TempVmms.RemoveAt(i);
this.ReplyToPlayer(player.IPlayer, string.Format(lang.GetMessage("AddingMapMarkerSuccess", this, player.IPlayer.Id), npc.userID));
}
}
// Unsubscribe from OnUseNPC hook if it is not needed anymore
if(this.TempVmms.Count == 0) Unsubscribe("OnUseNPC");
}
#endregion
#region Localization
/*
* Load default messages
*/
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["UsageHelp"] = "NPCVendingMapMarker v{0} - A Rust umod plugin to add in-game vending map markers to NPC's.\r\n" +
"Copyright(C) 2020 by Pinguin and released under GPLv3\r\n" +
"\r\n" +
"The following commands are available:\r\n" +
" npcvmm.add : Add a new NPC vending map marker.\r\n" +
" npcvmm.reset : Reset temporary NPC vending map marker data for current player.\r\n" +
" npcvmm.list : List all configured NPC vending map markers.\r\n" +
" npcvmm.del : Delete a single NPC vending map marker.\r\n" +
" npcvmm.clear : Delete all configured NPC vending map markers.\r\n" +
" npcvmm.refresh : Refresh all configured NPC vending map markers.\r\n" +
" npcvmm.debug : Toggle internal debugging on/off.\r\n" +
"\r\n" +
"For commands that take arguments, more help is available by executing them without any arguments.\r\n" +
"\r\n" +
"To be able to execute any NPCVendingMapMarker commands, you need to have the umod 'npcvendingmapmarker.admin' right assigned to your user.",
["DebugOn"] = "Switched debugging ON",
["DebugOff"] = "Switched debugging OFF",
["MissingShopName"] = "Usage: npcvmm.add <shop name>",
["UseNpcToAdd"] = "The next NPC you use will get a vending map marker with the name '{0}'",
["NpcAlreadyHasMapMarker"] = "The selected NPC '{0}' already has a vending map marker configured!",
["FailedSpawningMarker"] = "Unable to spawn vending map marker!",
["AddingMapMarkerSuccess"] = "Successfully added vending map marker to NPC '{0}'",
["AlreadyHaveTempVmm"] = "You can't add another marker until you finished adding the previous one! Use an NPC to add your previously configured map marker or do npcvmm.reset",
["ResetSuccessful"] = "Successfully removed temporary config values",
["ResetFailed"] = "No temporary config values available",
["TotalConfiguredMarkers"] = "You have a total of {0} NPC vending map marker(s) configured",
["MarkerDetails"] = "{0} @ {1} : '{2}'",
["MissingNpcId"] = "Usage: npcvmm.del <npc_id>",
["InvalidNpcId"] = "The given NPC ID is not valid!",
["NpcvmmRemoved"] = "The vending map marker for NPC id {0} was removed",
["UnknownNpcId"] = "No vending map marker for NPC id {0} configured",
["AllCleared"] = "All vending map markers cleared",
}, this);
}
#endregion
#region Console Commands
/*
* Print Usage info
*/
[Command("npcvmm")]
void CmdInfo(IPlayer player, string command, string[] args)
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("UsageHelp", this, player.Id), Version));
}
/*
* Toggle debug on/off
*/
[Command("npcvmm.debug"), Permission("npcvendingmapmarker.admin")]
void CmdDebug(IPlayer player, string command, string[] args)
{
this.config_data.debug = !this.config_data.debug;
if(this.config_data.debug) this.ReplyToPlayer(player, string.Format(lang.GetMessage("DebugOn", this, player.Id)));
else this.ReplyToPlayer(player, string.Format(lang.GetMessage("DebugOff", this, player.Id)));
Config.WriteObject<NPCVendingMapMarkerConfig>(this.config_data, true);
}
/*
* Add a new NPC vending map marker
*/
[Command("npcvmm.add"), Permission("npcvendingmapmarker.admin")]
void CmdAdd(IPlayer player, string command, string[] args)
{
BasePlayer base_player = player.Object as BasePlayer;
// Check command line args
if (args.Length != 1)
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("MissingShopName", this, player.Id)));
return;
}
// Make sure we don't already have temporary config values
bool flag = false;
foreach(TempVmm temp_vmm in this.TempVmms)
{
if(temp_vmm.request_uid == base_player.userID)
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("AlreadyHaveTempVmm", this, player.Id), args[0]));
flag = true;
break;
}
}
if(flag) return;
// Create temporary config values
TempVmm temp_vmm2;
temp_vmm2.request_uid = base_player.userID;
temp_vmm2.shop_name = args[0];
this.TempVmms.Add(temp_vmm2);
// Subscribe to OnUseNPC to receive npc id & position and tell player to use NPC now
Subscribe("OnUseNPC");
this.ReplyToPlayer(player, string.Format(lang.GetMessage("UseNpcToAdd", this, player.Id), args[0]));
}
/*
* Remove temporary config values
*/
[Command("npcvmm.reset"), Permission("npcvendingmapmarker.admin")]
void CmdReset(IPlayer player, string command, string[] args)
{
BasePlayer base_player = player.Object as BasePlayer;
bool flag = false;
for(int i = 0; i < this.TempVmms.Count; i++)
{
if(this.TempVmms[i].request_uid == base_player.userID)
{
this.TempVmms.RemoveAt(i);
flag = true;
break;
}
}
if(flag) this.ReplyToPlayer(player, string.Format(lang.GetMessage("ResetSuccessful", this, player.Id)));
else this.ReplyToPlayer(player, string.Format(lang.GetMessage("ResetFailed", this, player.Id)));
}
/*
* List all configured vending map markers
*/
[Command("npcvmm.list"), Permission("npcvendingmapmarker.admin")]
void CmdList(IPlayer player, string command, string[] args)
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("TotalConfiguredMarkers", this, player.Id), this.config_data.configured_markers.Count));
foreach (KeyValuePair<ulong, MarkerData> cm in this.config_data.configured_markers)
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("MarkerDetails", this, player.Id), cm.Key, cm.Value.position.ToString(), cm.Value.shop_name));
}
}
/*
* Delete a configured vending map markers
*/
[Command("npcvmm.del"), Permission("npcvendingmapmarker.admin")]
void CmdDel(IPlayer player, string command, string[] args)
{
BasePlayer base_player = player.Object as BasePlayer;
ulong npc_id = 0;
// Check command line args
if (args.Length != 1)
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("MissingNpcId", this, player.Id)));
return;
}
if (!ulong.TryParse(args[0], out npc_id))
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("InvalidNpcId", this, player.Id)));
return;
}
// Check if we have a configuration for the given NPC id
if(this.config_data.configured_markers.ContainsKey(npc_id))
{
// Remove npcvmm from config and despawn it
this.config_data.configured_markers.Remove(npc_id);
Config.WriteObject<NPCVendingMapMarkerConfig>(this.config_data, true);
this.RemoveMapMarker(npc_id);
this.ReplyToPlayer(player, string.Format(lang.GetMessage("NpcvmmRemoved", this, player.Id), npc_id));
}
else
{
this.ReplyToPlayer(player, string.Format(lang.GetMessage("UnknownNpcId", this, player.Id), npc_id));
}
}
/*
* Delete all configured vending map markers
*/
[Command("npcvmm.clear"), Permission("npcvendingmapmarker.admin")]
void CmdClear(IPlayer player, string command, string[] args)
{
this.ClearVendingMapMarkers();
this.config_data.configured_markers.Clear();
Config.WriteObject<NPCVendingMapMarkerConfig>(this.config_data, true);
this.ReplyToPlayer(player, string.Format(lang.GetMessage("AllCleared", this, player.Id)));
}
/*
* Refresh all configured vending map markers
*/
[Command("npcvmm.refresh"), Permission("npcvendingmapmarker.admin")]
void CmdRefresh(IPlayer player, string command, string[] args)
{
// Try to re-read ServerRewards data files
this.ReadServerRewardsData();
// Iterate over all spawned vmms and re-add them
Dictionary<ulong, VendingMachineMapMarker>.KeyCollection keys = this.map_markers.Keys;
this.LogDebug(string.Format("Refreshing {0} npcvmm(s)", keys.Count));
foreach (ulong key in keys.ToList())
{
// Update / remove npcvmms
if (this.config_data.configured_markers.ContainsKey(key))
{
this.LogDebug(string.Format("Refreshing npcvmm for npc {0}", key));
this.AddMapMarker(key, this.config_data.configured_markers[key]);
}
else
{
this.LogDebug(string.Format("Found unconfigured npcvmm for npc {0}.Removing", key));
this.RemoveMapMarker(key);
}
}
}
#endregion
#region Helper Functions
/*
* Add a vending map marker to the map
*/
private bool AddMapMarker(ulong _npc_id, MarkerData _marker_data)
{
this.LogDebug(string.Format("Spawning npcvmm for npc id {0} with name '{1}' at position {2}", _npc_id, _marker_data.shop_name, _marker_data.position.ToString()));
// Make sure to remove an already existing npcvmm first
this.RemoveMapMarker(_npc_id);
// Create and configure new marker
VendingMachineMapMarker vmmm = GameManager.server.CreateEntity("assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab", _marker_data.position, UnityEngine.Quaternion.identity, true) as VendingMachineMapMarker;
if (vmmm == null)
{
this.LogDebug("CreateEntity failed!");
return false;
}
vmmm.server_vendingMachine = null;
// Set busy flag to have a green symbol
vmmm.SetFlag(BaseEntity.Flags.Busy, true, false, true);
// Set shop name and add shop info if available
vmmm.markerShopName = _marker_data.shop_name;
vmmm.markerShopName += this.GetServerRewardsData(_npc_id.ToString());
// Spawn marker on map
vmmm.Spawn();
vmmm.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
// Add marker to our marker list
this.map_markers.Add(_npc_id, vmmm);
this.LogDebug(string.Format("Successfully spawned npcvmm for npc id {0} with name '{1}' at position {2}", _npc_id, _marker_data.shop_name, _marker_data.position.ToString()));
return true;
}
/*
* Remove a vending map marker from the map
*/
private bool RemoveMapMarker(ulong _npc_id)
{
// Search map marker, kill it and remove it from list
if(this.map_markers.ContainsKey(_npc_id))
{
this.LogDebug(string.Format("npcvmm for npc id {0} exists.Removing", _npc_id));
this.map_markers[_npc_id].Kill(BaseNetworkable.DestroyMode.None);
this.map_markers.Remove(_npc_id);
return true;
}
return false;
}
/*
* Check if a given NPC already has a configured vending map marker
*/
private bool HasMapMarker(ulong _npc_id)
{
return this.map_markers.ContainsKey(_npc_id);
}
/*
* Remove all added vending map markers
*/
private void ClearVendingMapMarkers()
{
Dictionary<ulong, VendingMachineMapMarker>.ValueCollection markers = this.map_markers.Values;
this.LogDebug(string.Format("Removing {0} npcvmm(s)", markers.Count));
foreach (VendingMachineMapMarker map_marker in markers)
{
// Remove map marker from map and our marker list
map_marker.Kill(BaseNetworkable.DestroyMode.None);
}
this.map_markers.Clear();
}
/*
* Helper functions to send messages to players / console
*/
private void ReplyToPlayer(IPlayer player, string msg)
{
player.Reply(msg);
}
private void Log(string msg)
{
Puts(msg);
}
private void LogDebug(string msg)
{
if(this.config_data.debug)
{
this.Log("DEBUG :: " + msg);
}
}
#endregion
}
}