C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*
TODO:
- Add config options to customize sign color, size, etc.- Move all messages to config for localization
*/
using System;
using System.Collections;
using System.Collections.Generic;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("DeathSigns", "Wulf/lukespragg", "0.1.0", ResourceId = 1462)]
[Description("Creates dynamic signs that show the server death count.")]
class DeathSigns : RustPlugin
{
// Do NOT edit this file, instead edit DeathSigns.json in server/<identity>/oxide/config
#region Configuration
// Messages
string NoPermission => GetConfig("NoPermission", "Sorry, you can't use 'deathsign' right now");
string NoSignsFound => GetConfig("NoSignFound", "No usable signs could be found");
// Settings
string ChatCommand => GetConfig("ChatCommand", "deathsign");
protected override void LoadDefaultConfig()
{
// Messages
Config["NoPermission"] = NoPermission;
Config["NoSignsFound"] = NoSignsFound;
// Settings
Config["ChatCommand"] = ChatCommand;
SaveConfig();
}
#endregion
#region Data Storage
static StoredData storedData;
class StoredData
{
public Dictionary<uint, SignData> Signs = new Dictionary<uint, SignData>();
public int Deaths;
public StoredData()
{
}
}
class SignData
{
public uint TextureId;
public SignData()
{
}
public SignData(Signage sign)
{
TextureId = sign.textureID;
}
}
#endregion
#region General Setup
void Loaded()
{
LoadDefaultConfig();
storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
permission.RegisterPermission("deathsigns.admin", this);
cmd.AddChatCommand(ChatCommand, this, "SignChatCmd");
Puts("Deaths: " + storedData.Deaths + ", Signs: " + storedData.Signs.Count);
}
void OnServerInitialized()
{
webObject = new GameObject("WebObject");
uWeb = webObject.AddComponent<UnityWeb>();
}
#endregion
#region Unity WWW
GameObject webObject;
UnityWeb uWeb;
class QueueItem
{
public string url;
public Signage sign;
public BasePlayer sender;
public QueueItem(string ur, BasePlayer se, Signage si)
{
url = ur;
sender = se;
sign = si;
}
}
class UnityWeb : MonoBehaviour
{
const int MaxActiveLoads = 3;
static readonly List<QueueItem> QueueList = new List<QueueItem>();
static byte activeLoads;
public void Add(string url, BasePlayer player, Signage sign)
{
QueueList.Add(new QueueItem(url, player, sign));
if (activeLoads < MaxActiveLoads) Next();
}
void Next()
{
activeLoads++;
var qi = QueueList[0];
QueueList.RemoveAt(0);
var www = new WWW(qi.url);
StartCoroutine(WaitForRequest(www, qi));
}
IEnumerator WaitForRequest(WWW www, QueueItem info)
{
yield return www;
var player = info.sender;
if (www.error == null)
{
var sign = info.sign;
if (sign.textureID > 0U) FileStorage.server.Remove(sign.textureID, FileStorage.Type.png, sign.net.ID);
sign.textureID = FileStorage.server.Store(www.bytes, FileStorage.Type.png, sign.net.ID, 0U);
sign.SendNetworkUpdate();
player.SendMessage("Death sign created!");
}
else
{
player.ChatMessage(www.error);
}
activeLoads--;
if (QueueList.Count > 0) Next();
}
}
#endregion
#region Chat Command
void SignChatCmd(BasePlayer player)
{
if (!HasPermission(player, "deathsigns.admin"))
{
PrintToChat(player, NoPermission);
return;
}
// Check for sign to use
RaycastHit hit;
Signage sign = null;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, 2f)) sign = hit.transform.GetComponentInParent<Signage>();
if (sign == null)
{
PrintToChat(player, NoSignsFound);
return;
}
if (storedData.Signs.ContainsKey(sign.net.ID))
{
PrintToChat(player, "Already a death sign!");
return;
}
// Create sign image
var text = $"{storedData.Deaths}+{(storedData.Deaths == 1 ? "death" : "deaths")}";
const string bgColor = "ffffff";
const string textColor = "000000";
const int textSize = 80;
const int width = 350;
const int height = 150;
var url = $"http://placeholdit.imgix.net/~text?txtsize={textSize}&txt={text}&w={width}&h={height}";
uWeb.Add(url, player, sign);
// Store updated data
var info = new SignData(sign);
storedData.Signs.Add(sign.net.ID, info);
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
// Lock sign to prevent player edits
sign.SetFlag(BaseEntity.Flags.Locked, true);
sign.SendNetworkUpdate();
}
#endregion
#region Sign Updating/Cleanup
void OnEntityDeath(BaseEntity entity)
{
// Add player death to sign(s)
var player = entity as BasePlayer;
if (player)
{
storedData.Deaths++;
var signs = 0;
foreach (var id in storedData.Signs)
{
// Find sign entity
var sign = BaseNetworkable.serverEntities.Find(id.Key) as Signage;
// Create sign image
var text = $"{storedData.Deaths}+{(storedData.Deaths == 1 ? "death" : "deaths")}";
const string bgColor = "ffffff";
const string textColor = "000000";
const int textSize = 80;
const int width = 350;
const int height = 150;
var url = $"http://placeholdit.imgix.net/~text?txtsize={textSize}&txt={text}&w={width}&h={height}";
uWeb.Add(url, player, sign);
signs++;
}
Puts($"{storedData.Deaths} {(storedData.Deaths == 1 ? "death" : "deaths")}, {signs} signs updated!");
}
// Remove data for destroyed sign
var signage = entity as Signage;
if (signage) storedData.Signs.Remove(signage.net.ID);
// Store updated data
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
}
void Unload() => UnityEngine.Object.Destroy(webObject);
#endregion
#region Helper Methods
T GetConfig<T>(string name, T defaultValue)
{
if (Config[name] == null) return defaultValue;
return (T)Convert.ChangeType(Config[name], typeof(T));
}
bool HasPermission(BasePlayer player, string perm) => permission.UserHasPermission(player.UserIDString, perm);
#endregion
}
}