C#:
using Oxide.Core;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("NpcOverlay", "Flutes", "1.0.1")]
[Description("Enhances the Rust gaming environment by displaying customizable text overlays above NPCs, providing context or additional information.")]
public class NpcOverlay : RustPlugin
{
public static NpcOverlay Instance { get; private set; }
public static NpcOverlaysData Data { get; private set; }
private List<PlayerController> m_players = new List<PlayerController>();
private void OnServerInitialized()
{
Instance = this;
Data = NpcOverlaysData.Load();
Subscribe("OnEnterNPC");
Subscribe("OnExitNPC");
}
private void Unload()
{
for (int i = 0; i < m_players.Count; i++)
{
m_players[i].Stop();
}
}
public void ShowOverlay(BasePlayer owner, Vector3 pos, string npcId)
{
string text = "";
if (Data.Overlays.ContainsKey(npcId) == false)
{
return;
}
TextData textData = Data.Overlays[npcId];
text = Lang(textData.LangKey, owner.UserIDString);
pos += textData.LocalOffset;
if (string.IsNullOrEmpty(text))
{
Instance.Puts($"Not key {npcId} found on lang");
return;
}
if (!owner.IsAdmin)
{
owner.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, true);
owner.SendNetworkUpdateImmediate();
owner.SendConsoleCommand("ddraw.text", 1f, textData.Color, pos, text);
owner.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, false);
owner.SendNetworkUpdateImmediate();
}
else
{
owner.SendConsoleCommand("ddraw.text", 1f, textData.Color, pos, text);
}
}
public class PlayerController
{
public BasePlayer Player { get; private set; }
public BasePlayer Npc { get; private set; }
private Timer m_timerTalk;
public PlayerController(BasePlayer player, BasePlayer npc)
{
Player = player;
Npc = npc;
}
public void Start()
{
StartRoutineTalkOverlay();
}
public void Stop()
{
m_timerTalk.Reset();
m_timerTalk.Destroy();
}
private void StartRoutineTalkOverlay()
{
m_timerTalk = Instance.timer.Every(1.0f, () =>
{
if (Npc == null || Npc.IsDestroyed)
return;
Instance.ShowOverlay(Player, Npc.transform.position, Npc.UserIDString);
});
}
}
private void OnEnterNPC(BasePlayer npc, BasePlayer player)
{
if (npc == null || player == null)
return;
if (Data.Overlays.ContainsKey(npc.UserIDString) == false)
return;
PlayerController p = m_players.Find(x => x.Player == player && x.Npc == npc);
if (p == null)
{
p = new PlayerController(player, npc);
m_players.Add(p);
p.Start();
}
}
private void OnLeaveNPC(BasePlayer npc, BasePlayer player)
{
if (npc == null || player == null)
return;
if (Data.Overlays.ContainsKey(npc.UserIDString) == false)
return;
PlayerController p = m_players.Find(x => x.Player == player && x.Npc == npc);
if (p != null)
{
m_players.Remove(p);
p.Stop();
}
}
#region Lang
public string Lang(string key, string id = null, params object[] args)
{
try
{
return string.Format(lang.GetMessage(key, this, id), args);
}
catch (Exception)
{
PrintError($"Error in the language formatting of '{key}'. (userid: {id}. lang: {lang.GetLanguage(id)}. args: {string.Join(" ,", args)})");
throw;
}
}
#endregion
#region Data
public class NpcOverlaysData
{
public Dictionary<string, TextData> Overlays = new Dictionary<string, TextData>();
public static NpcOverlaysData Load()
{
NpcOverlaysData database = null;
var file = Interface.Oxide.DataFileSystem.GetFile($"{Instance.Name}");
if (file == null)
{
Instance.Puts($"NpcOverlaysData Data file {Instance.Name} not found");
return null;
}
else
{
database = file.ReadObject<NpcOverlaysData>();
}
return database;
}
}
public class TextData
{
public Color Color = Color.yellow;
public Vector3 LocalOffset = Vector3.up;
public string LangKey = "";
}
#endregion
}
}