C#:
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using Oxide.Game.Rust.Cui;
using ConVar;
using System.Linq;
namespace Oxide.Plugins
{
[Info("SkipNight", "Mercury", "0.0.5")]
[Description("Самый лучший пионер Mercury")]
class SkipNight : RustPlugin
{
#region Vars
public Dictionary<BasePlayer, VoteResult> VotesPlayer = new Dictionary<BasePlayer, VoteResult>();
internal class VoteResult
{
public double Cooldown;
public bool Vote;
}
bool VoteActive = false;
#endregion
#region Reference
[PluginReference] Plugin ImageLibrary, IQChat, IQFakeActive;
bool CanTake(BasePlayer player) => !player.inventory.containerMain.IsFull() || !player.inventory.containerBelt.IsFull();
public string GetImage(string shortname, ulong skin = 0) => (string)ImageLibrary?.Call("GetImage", shortname, skin);
public bool AddImage(string url, string shortname, ulong skin = 0) => (bool)ImageLibrary?.Call("AddImage", url, shortname, skin);
int FakeOnline => (int)IQFakeActive?.Call("GetOnline");
void SyncReservedFinish()
{
if (!config.IQFakeActive) return;
PrintWarning("SkipNight - успешно синхронизирована с IQFakeActive");
PrintWarning("=============SYNC==================");
}
#endregion
#region Configuration
private static Configuration config = new Configuration();
private class Configuration
{
[JsonProperty("Включить поддержку IQFakeActive(true - да/false - нет)")]
public bool IQFakeActive;
[JsonProperty("Сколько минимум игроков должно быть на сервере для запуска голосования(будут учитываться и игроки IQFakeActive, если включено)")]
public int VotePlayerCount;
[JsonProperty("Во сколько начинать голосование (игровое время)")]
public int TimeVoteCount;
[JsonProperty("Какое время устанавливать в случае пропуска ночи")]
public int TimeSetDay;
[JsonProperty("Сколько времени будет длиться голосование")]
public int TimeSkip;
[JsonProperty("Раз в сколько секунд можно вернуть голос")]
public int CooldownVote;
[JsonProperty("Настройка интерфейса")]
public SettingUI Interface = new SettingUI();
internal class SettingUI
{
[JsonProperty("Иконка для кнопки дня(png)")]
public string IconDay;
[JsonProperty("Иконка для кнопки ночи(png)")]
public string IconNight;
public string AnchorMin;
public string AnchorMax;
public string OffsetMin;
public string OffsetMax;
}
public static Configuration GetNewConfiguration()
{
return new Configuration
{
IQFakeActive = false,
VotePlayerCount = 10,
TimeSkip = 120,
TimeVoteCount = 18,
TimeSetDay = 12,
CooldownVote = 30,
Interface = new SettingUI
{
IconDay = "https://i.imgur.com/QQq8i8C.png",
IconNight = "https://i.imgur.com/3Wpn1iY.png",
AnchorMin = "1 0",
AnchorMax = "1 0",
OffsetMin = "-455 10",
OffsetMax = "-390 70"
}
};
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
}
catch
{
PrintWarning("Ошибка #1461" + $"чтения конфигурации 'oxide/config/{Name}', создаём новую конфигурацию!!");
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
protected override void LoadDefaultConfig() => config = Configuration.GetNewConfiguration();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Metods
public bool CanVote()
{
if (VoteActive) return false;
int Online = IQFakeActive ? config.IQFakeActive ? FakeOnline : BasePlayer.activePlayerList.Count : BasePlayer.activePlayerList.Count;
if (Online >= config.VotePlayerCount)
if ((int)TOD_Sky.Instance.Cycle.Hour == config.TimeVoteCount)
return true;
else return false;
else return false;
}
public bool CanVoteUser(BasePlayer player) => VotesPlayer.ContainsKey(player);
public void VotePlayer(BasePlayer player)
{
if (VotesPlayer[player].Cooldown <= CurrentTime())
{
bool Vote = VotesPlayer[player].Vote ? false : true;
VotesPlayer[player].Vote = Vote;
VotesPlayer[player].Cooldown = config.CooldownVote + CurrentTime();
}
else
{
SendPlayer(player, String.Format(lang.GetMessage("VOTE_COOLDOWN", this), config.CooldownVote, FormatTime(TimeSpan.FromSeconds(VotesPlayer[player].Cooldown - CurrentTime()))));
return;
}
SendPlayer(player, lang.GetMessage("VOTE_ACCESS", this));
UI_VoteShow(player);
}
public void VoteResults()
{
int VoteTrue = VotesPlayer.Count(t => t.Value.Vote == true);
int VoteFalse = VotesPlayer.Count(f => f.Value.Vote == false);
if(VoteTrue > VoteFalse)
{
TOD_Sky.Instance.Cycle.Hour = config.TimeSetDay;
SendChat(lang.GetMessage("VOTE_NIGHT", this));
}
else SendChat(lang.GetMessage("VOTE_DAY", this));
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++)
{
var p = BasePlayer.activePlayerList[i];
if (p == null) return;
CuiHelper.DestroyUi(p, VOTE_PARENT);
}
VoteActive = false;
VotesPlayer.Clear();
}
public void VoteStart()
{
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++)
{
var p = BasePlayer.activePlayerList[i];
if (p == null) return;
if (!CanVoteUser(p))
VotesPlayer.Add(p, new VoteResult { Vote = false, Cooldown = 0 });
UI_VoteShow(p);
}
SendChat(lang.GetMessage("VOTE_START", this));
VoteActive = true;
timer.Once(config.TimeSkip, () => { VoteResults(); });
}
#endregion
#region Hooks
private void Unload()
{
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++)
{
var p = BasePlayer.activePlayerList[i];
CuiHelper.DestroyUi(p, VOTE_PARENT);
}
}
private void OnServerInitialized()
{
AddImage(config.Interface.IconDay, "DayButton");
AddImage(config.Interface.IconNight, "NightButton");
timer.Every(10f, () =>
{
if (CanVote())
VoteStart();
});
}
#endregion
#region UI
public static string VOTE_PARENT = "VOTE_PARENT_SHOWUI";
void UI_VoteShow(BasePlayer player)
{
CuiElementContainer container = new CuiElementContainer();
CuiHelper.DestroyUi(player, VOTE_PARENT);
string Icon = CanVoteUser(player) ? VotesPlayer[player].Vote ? "DayButton" : "NightButton" : "DayButton";
var UI = config.Interface;
container.Add(new CuiElement
{
Parent = "Overlay",
Name = VOTE_PARENT,
Components =
{
new CuiRawImageComponent { Png = GetImage(Icon) },
new CuiRectTransformComponent { AnchorMin = UI.AnchorMin, AnchorMax = UI.AnchorMax, OffsetMin = UI.OffsetMin, OffsetMax = UI.OffsetMax }
}
});
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "0 0",OffsetMin = "-30 -10", OffsetMax = "100 9" },
Text = { Text = "<b>Пропуск ночи</b>", Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleCenter, FontSize = 14 }
}, VOTE_PARENT);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
Button = { Command = "vote", Color = "0 0 0 0"},
Text = { Text = "", Color = HexToRustFormat("#FFBBB0FF"), Align = TextAnchor.MiddleCenter }
}, VOTE_PARENT);
CuiHelper.AddUi(player, container);
}
#endregion
#region Command
[ConsoleCommand("vote")]
void VoteCommand(ConsoleSystem.Arg arg)
{
BasePlayer player = arg.Player();
VotePlayer(player);
}
[ChatCommand("day")]
void StartVoteDay(BasePlayer player)
{
if(player.IsAdmin)
VoteStart();
}
#endregion
#region Lang
private new void LoadDefaultMessages()
{
PrintWarning("Языковой файл загружается...");
lang.RegisterMessages(new Dictionary<string, string>
{
["VOTE_START"] = "<size=14>Voting to pass the night has begun!</size>",
["VOTE_DAY"] = "<size=14>Voting is over!\nNight will not be missed</size>",
["VOTE_NIGHT"] = "<size=14>Voting is over!\nNight skipped</size>",
["VOTE_ACCESS"] = "<size=14>Your vote has been accepted!</size>",
["VOTE_COOLDOWN"] = "<size=14>You can change your voice back once a {0} seconds!\nLeft {1}</size>",
}, this);
lang.RegisterMessages(new Dictionary<string, string>
{
["VOTE_START"] = "<size=14>Голосование за пропуск ночи началось!</size>",
["VOTE_DAY"] = "<size=14>Голосование закончено!\nНочь не будет пропущена</size>",
["VOTE_NIGHT"] = "<size=14>Голосование закончено!\nНочь пропущена</size>",
["VOTE_ACCESS"] = "<size=14>Ваш голос принят!</size>",
["VOTE_COOLDOWN"] = "<size=14>Вы можете изменить голос обратно раз в {0} секунд!\nОсталось {1}</size>",
}, this, "ru");
PrintWarning("Языковой файл загружен успешно");
}
#endregion
#region Helps
static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
static double CurrentTime() => DateTime.UtcNow.Subtract(epoch).TotalSeconds;
private static string HexToRustFormat(string hex)
{
Color color;
ColorUtility.TryParseHtmlString(hex, out color);
return string.Format("{0:F2} {1:F2} {2:F2} {3:F2}", color.r, color.g, color.b, color.a);
}
public void SendChat(string Message, Chat.ChatChannel channel = Chat.ChatChannel.Global)
{
if (IQChat)
IQChat?.Call("API_ALERT", Message);
else
{
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++)
{
var p = BasePlayer.activePlayerList[i];
p.SendConsoleCommand("chat.add", channel, 0, Message);
}
}
}
public void SendPlayer(BasePlayer player,string Message)
{
if (IQChat)
IQChat?.Call("API_ALERT_PLAYER", player, Message);
else player.SendConsoleCommand("chat.add", Chat.ChatChannel.Global, 0, Message);
}
public static string FormatTime(TimeSpan time)
{
string result = string.Empty;
if (time.Days != 0)
result += $"{Format(time.Days, "дней", "дня", "день")} ";
if (time.Hours != 0)
result += $"{Format(time.Hours, "часов", "часа", "час")} ";
if (time.Minutes != 0)
result += $"{Format(time.Minutes, "минут", "минуты", "минута")} ";
if (time.Seconds != 0)
result += $"{Format(time.Seconds, "секунд", "секунды", "секунда")} ";
return result;
}
private static string Format(int units, string form1, string form2, string form3)
{
var tmp = units % 10;
if (units >= 5 && units <= 20 || tmp >= 5 && tmp <= 9)
return $"{units} {form1}";
if (tmp >= 2 && tmp <= 4)
return $"{units} {form2}";
return $"{units} {form3}";
}
#endregion
}
}