Иконка ресурса

FREE SmoothRestart : 1.0.1 1.0.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Linq;
using System.Text;
using Oxide.Core.Configuration;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("SmoothRestart", "Fujikura/Visagalis", "1.0.1", ResourceId = 1826)]
    public class SmoothRestart : RustPlugin
    {
        bool Changed;
		JsonSerializerSettings jsonsettings;
		DateTime restartTime = DateTime.MinValue;
		Dictionary<BasePlayer, Timer> timers = new Dictionary<BasePlayer, Timer>();
		Dictionary<string, string> userAgent;
        Timer _blogTimer = null;
		Timer _oxideTimer = null;
		int serverOxideVersion;
		
		bool initCheckDevblog;
		bool initCheckOxideBuild;
		bool simulationActive;
		bool patchRestartRunning;
		
		int lastMinute;
		int lastSecond;
		int currentCountDown;
		bool countDownActive;
		bool secondsActive;
		bool timerActivated;
		bool newDevblogDetected;
		bool newOxideBuildDetected;
		
		UIColor deathNoticeShadowColor = new UIColor(0.1, 0.1, 0.1, 0.8);
        UIColor deathNoticeColor = new UIColor(0.85, 0.85, 0.85, 0.1);
		
		Dictionary<string, object> rebootTimes = new Dictionary<string, object>();
		List<object> countDownMinutes = new List<object>();
		List<object> countDownSeconds = new List<object>();
		bool useTimers;
		
		int currentDevblog;
		int currentOxideBuild;
		int oxideCheckHoursBack;
		int checkIntervalMinutes;
		bool enableAutoChecks;
		bool enableAutoReboot;
		int autoRebootCountDown;
		bool notifyOnlineAdmins;

		bool SimpleUI_Enable;
		int SimpleUI_FontSize;
		float SimpleUI_Top;
		float SimpleUI_Left;
		float SimpleUI_MaxWidth;
		float SimpleUI_MaxHeight;
		float SimpleUI_HideTimer;
						
		static Dictionary<string, object> defaultRebootTimes()
		{
			var dp = new Dictionary<string, object>();
			dp.Add("23:30","30");
			dp.Add("11:15","45");
			return dp;
		}
		
		static List<object> defaultCountDownMinutes()
		{
			var dp = new List<object>();
			dp.Add(60);
			dp.Add(45);
			dp.Add(30);
			dp.Add(15);
			dp.Add(10);
			dp.Add(5);
			dp.Add(4);
			dp.Add(3);
			dp.Add(2);
			dp.Add(1);			
			return dp;
		}
		
		static List<object> defaultCountDownSeconds()
		{
			var dp = new List<object>();
			dp.Add(50);
			dp.Add(40);
			dp.Add(30);
			dp.Add(20);
			dp.Add(10);
			dp.Add(5);
			dp.Add(4);
			dp.Add(3);
			dp.Add(2);
			dp.Add(1);
			return dp;
		}
		
		List<Regex> regexTags = new List<Regex>
        {
            new Regex(@"<color=.+?>", RegexOptions.Compiled),
            new Regex(@"<size=.+?>", RegexOptions.Compiled)
        };

        List<string> tags = new List<string>
        {
            "</color>",
            "</size>",
            "<i>",
            "</i>",
            "<b>",
            "</b>"
        };
		
		object GetConfig(string menu, string datavalue, object defaultValue)
		{
			var data = Config[menu] as Dictionary<string, object>;
			if (data == null)
			{
				data = new Dictionary<string, object>();
				Config[menu] = data;
				Changed = true;
			}
			object value;
			if (!data.TryGetValue(datavalue, out value))
			{
				value = defaultValue;
				data[datavalue] = value;
				Changed = true;
			}
			return value;
		}		
		
		void LoadVariables()
		{
			rebootTimes = (Dictionary<string, object>)GetConfig("Timers", "RebootTimes", defaultRebootTimes());
			countDownMinutes = (List<object>)GetConfig("Settings", "ShowMinutes", defaultCountDownMinutes());
			countDownSeconds = (List<object>)GetConfig("Settings", "ShowSeconds", defaultCountDownSeconds());
			useTimers = Convert.ToBoolean(GetConfig("Timers", "useTimers", false));
			
			currentDevblog = Convert.ToInt32(GetConfig("Checks", "currentDevblog", 0));
			currentOxideBuild = Convert.ToInt32(GetConfig("Checks", "currentOxideBuild", 0));
			oxideCheckHoursBack = Convert.ToInt32(GetConfig("Checks", "oxideCheckHoursBack", 2));
			checkIntervalMinutes = Convert.ToInt32(GetConfig("Checks", "checkIntervalMinutes", 5));
			enableAutoChecks = Convert.ToBoolean(GetConfig("Checks", "enableAutoChecks", true));
			enableAutoReboot = Convert.ToBoolean(GetConfig("Checks", "enableAutoReboot", false));
			autoRebootCountDown = Convert.ToInt32(GetConfig("Checks", "autoRebootCountDown", 3));
			notifyOnlineAdmins = Convert.ToBoolean(GetConfig("Checks", "notifyOnlineAdmins", true));
			
			SimpleUI_Enable = Convert.ToBoolean(GetConfig("SimpleUI", "SimpleUI_Enable", true));
			SimpleUI_FontSize = Convert.ToInt32(GetConfig("SimpleUI", "SimpleUI_FontSize", 30));
			SimpleUI_Top = Convert.ToSingle(GetConfig("SimpleUI", "SimpleUI_Top", 0.1));
			SimpleUI_Left = Convert.ToSingle(GetConfig("SimpleUI", "SimpleUI_Left", 0.1));
			SimpleUI_MaxWidth = Convert.ToSingle(GetConfig("SimpleUI", "SimpleUI_MaxWidth", 0.8));
			SimpleUI_MaxHeight = Convert.ToSingle(GetConfig("SimpleUI", "SimpleUI_MaxHeight", 0.05));
			SimpleUI_HideTimer = Convert.ToSingle(GetConfig("SimpleUI", "SimpleUI_HideTimer", 10));

			if (!Changed) return;
			SaveConfig();
			Changed = false;
		}
		
		void LoadDefaultMessages()
		{
			lang.RegisterMessages(new Dictionary<string, string>
			                      {
									{"RestartInit", "<color=orange>Server will restart in <color=red>{0}</color> minutes!</color>"},
									{"RestartInitPatch", "<color=red>Server Patch</color> <color=orange>restart in <color=red>{0}</color> minutes!</color>"},
									{"RestartInitSec", "<color=orange>Server will restart in <color=red>{0}</color> seconds!</color>"},
									{"RestartCancel", "<color=green>Server restart stopped!</color>"},
									
									{"ManualInit", "<color=silver>Manual countdown will start at next full minute</color>"},									
									{"ManualCancel", "<color=silver>Manual Timer was canceled</color>"},
									{"DevblogDetected", "<color=orange>New DevBlog <color=green>{0}</color> detected !!!</color>"},
									{"OxideBuildDetected", "<color=orange>New OxideBuild <color=green>{0}</color> detected !!!</color>"},									
									},this);
		}

		protected override void LoadDefaultConfig()
		{
			Config.Clear();
			LoadVariables();
		}

		void Init()
		{
			LoadVariables();
			LoadDefaultMessages();
			lastMinute = DateTime.Now.Minute;
			lastSecond = DateTime.Now.Second;
			currentCountDown = 0;
			jsonsettings = new JsonSerializerSettings();
            jsonsettings.Converters.Add(new KeyValuesConverter()); 
			newDevblogDetected = false;
			newOxideBuildDetected = false;
			userAgent = new Dictionary<string, string>();
			userAgent.Add("User-Agent", "OxideMod");
			serverOxideVersion = Convert.ToInt32(Oxide.Core.OxideMod.Version.Patch);
			initCheckDevblog = true;
			initCheckOxideBuild = true;
			simulationActive = false;
			patchRestartRunning = false;
		}	

        void OnServerInitialized()
        {
            if (!permission.PermissionExists("smoothrestart.canrestart"))
                permission.RegisterPermission("smoothrestart.canrestart", this);
				CheckDevBlog(3);
				CheckOxideCommits(168);
			if (enableAutoChecks)
				_blogTimer = timer.Every(checkIntervalMinutes*60, () => CheckDevBlog());
        }	
		
				
		void OnTick()
		{
			if ((!secondsActive && lastMinute == DateTime.Now.Minute)) return;
			if (secondsActive && lastSecond == DateTime.Now.Second) return;
			if (secondsActive)
			{
				lastSecond = DateTime.Now.Second;
				if (currentCountDown == 0)
				{
					if (!simulationActive)
					{
						ConVar.Global.quit(new ConsoleSystem.Arg(null));
						return;
					}
					else
					{
						secondsActive = false;
						timerActivated = false;
						simulationActive = false;
						oxideCheckHoursBack = (int)Config["Checks", "oxideCheckHoursBack"];
						enableAutoReboot = (bool)Config["Checks", "enableAutoReboot"];
						Puts("Patch simulation finished");
						return;
					}
				}
				if (countDownSeconds.Contains(currentCountDown))
					DoSmoothRestart(currentCountDown, false);
				currentCountDown--;
				return;
				// breaks here on times under a minute
			}
			lastMinute = DateTime.Now.Minute;
			if (countDownActive)
			{
				if (countDownMinutes.Contains(currentCountDown))
					DoSmoothRestart(currentCountDown);
				currentCountDown--;
				//switchers over to seconds if timer reached 0
				if (currentCountDown == 0)
				{
					secondsActive = true;
					lastSecond = DateTime.Now.Second;
					currentCountDown = 59;
					return;
				}
				return;
			}
			if ((useTimers && !countDownActive && rebootTimes.ContainsKey(DateTime.Now.ToString("HH:mm"))) || timerActivated)
			{
				if (!timerActivated)
					currentCountDown = Convert.ToInt32(rebootTimes[DateTime.Now.ToString("HH:mm")]);
				countDownActive = true;
				DoSmoothRestart(currentCountDown);
				currentCountDown--;
			}
		}
		
		void CheckDevBlog(int countNews = 3)
        {
			var url = $"http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=252490&count={countNews}&maxlength=1&format=json";
			try { webrequest.EnqueueGet(url, (code, response) => APIResponse(code, response, "devblog", countNews), this); }
			catch { if (countNews != 3) timer.Once(60f, () => CheckDevBlog(6)); }
		}

		void CheckOxideCommits(int hoursBack = 0)
        {
			if (hoursBack == 0)
				hoursBack = oxideCheckHoursBack;
			var sinceDate = DateTime.Now.AddHours(-hoursBack).ToString("yyyy-MM-ddTHH:mm:ssZ");
			var url = $"https://api.github.com/repos/OxideMod/Snapshots/commits?since={sinceDate}";
			Dictionary<string, string> userAgent  = new Dictionary<string, string>();
			userAgent.Add("User-Agent", "OxideMod");
			try { webrequest.EnqueueGet(url, (code, response) => APIResponse(code, response, "oxide", hoursBack), this, userAgent); }
			catch { if (hoursBack == 168) timer.Once(60f, () => CheckOxideCommits(168));}
		}		

		void APIResponse(int code, string response, string apiType, int numberCheck)
        {
			if (!(response == null || code != 200) && apiType == "devblog")
			{
				var jsonresponse1 = JsonConvert.DeserializeObject<Dictionary<string, object>>(response, jsonsettings);
				if (!(jsonresponse1["appnews"] is Dictionary<string, object>)) return;
				var items = ((jsonresponse1["appnews"] as Dictionary<string, object>)["newsitems"] as List<object>).ToArray();
				foreach (Dictionary<string, object> info in items.Where(p => (p as Dictionary<string, object>)["title"].ToString().Contains("Devblog")))
				{
					if (info["title"].ToString().Contains("Devblog"))
					{
						if (currentDevblog == 0 || initCheckDevblog)
						{
							var resultBlog = Convert.ToInt32((info["title"].ToString().Replace("Devblog ", "")));
							if (resultBlog != currentDevblog)
							{
								currentDevblog = resultBlog;
								Config["Checks", "currentDevblog"] = currentDevblog;
								Config.Save();
							}
							if (initCheckDevblog) initCheckDevblog = false;
							break;
						}
						var checkedDevblog = Convert.ToInt32((info["title"].ToString().Replace("Devblog ", "")));
						bool blogChanged = false;
						if (currentDevblog != checkedDevblog)
						{
							blogChanged = true;
							currentDevblog = checkedDevblog;
							Config["Checks", "currentDevblog"] = currentDevblog;
							Config.Save();
						}
						if (blogChanged)
						{
							Puts(StripTags(string.Format(lang.GetMessage("DevblogDetected", this), currentDevblog)));
							if (notifyOnlineAdmins)
								foreach (var player in BasePlayer.activePlayerList.Where(p => p.IsAdmin()).ToList())
									SendReply(player, string.Format(lang.GetMessage("DevblogDetected", this), currentDevblog));
							newDevblogDetected = true;
							if ( _blogTimer == null || _blogTimer.Destroyed)
								return;
							_blogTimer.Destroy();
							_blogTimer = null;
							_oxideTimer = timer.Every(60f, () => CheckOxideCommits());
						}
						break;
					}
				}
			}
			else if (!(response == null || code != 200) && apiType == "oxide")
			{
				var jsonresponse2 = JsonConvert.DeserializeObject<List<object>>(response, jsonsettings);
				if (!(jsonresponse2 is List<object>) || jsonresponse2.Count == 0) return;
				Dictionary <string,object> commitCheck = jsonresponse2.First() as Dictionary <string,object>;
				string message = (commitCheck["commit"] as Dictionary <string,object>)["message"].ToString().Replace("Oxide build ", "");  
				if (!message.Contains("Oxide build") &&  jsonresponse2.Count > 1)
				{
					foreach (Dictionary <string,object> entry in jsonresponse2)
					{
						if ((entry["commit"] as Dictionary <string,object>)["message"].ToString().Contains("Oxide build"))
						{
							message = (entry["commit"] as Dictionary <string,object>)["message"].ToString().Replace("Oxide build ", "");
							break;							
						}
					}
				}
				else
					message = $"Oxide build {Oxide.Core.OxideMod.Version.Patch} from";
				var buildNum = Convert.ToInt32(message.Substring(0, message.LastIndexOf(" from") + 1));
				if (currentOxideBuild == 0 || initCheckOxideBuild)
				{
					if ( buildNum != currentOxideBuild)
					{
						currentOxideBuild = buildNum;
						Config["Checks", "currentOxideBuild"] = currentOxideBuild;
						Config.Save();
					}
					if (initCheckOxideBuild) initCheckOxideBuild = false;
					return;
				}
				bool buildChanged = false;
				if (currentOxideBuild != buildNum)
				{
					buildChanged = true;
					currentOxideBuild = buildNum;
					Config["Checks", "currentOxideBuild"] = currentOxideBuild;
					Config.Save();
				}
				if (buildChanged)
				{
					Puts(StripTags(string.Format(lang.GetMessage("OxideBuildDetected", this), currentOxideBuild)));
					if (notifyOnlineAdmins)
						foreach (var player in BasePlayer.activePlayerList.Where(p => p.IsAdmin()).ToList())
							SendReply(player, string.Format(lang.GetMessage("OxideBuildDetected", this), currentOxideBuild));
					newOxideBuildDetected = true;
					if ( _oxideTimer == null || _oxideTimer.Destroyed)
						return;
					_oxideTimer.Destroy();
					_oxideTimer = null;
					CheckAutoRestart();
				}
			}
		}
				
		void CheckAutoRestart()
		{
			if (!enableAutoReboot) return;
			if (!newDevblogDetected || !newOxideBuildDetected) return;
			patchRestartRunning = true;
			timerActivated = true;
			currentCountDown = autoRebootCountDown;
		}		
		        
		[ConsoleCommand("simulatepatch")]
        void checkOxideCommits(ConsoleSystem.Arg arg)
        {
            if(arg.connection != null && arg.connection.authLevel < 2) return;
			currentDevblog--;
			currentOxideBuild--;
			SendReply(arg, "Changed current Devblog and OxideBuild numbers to simulate successful checks");
			simulationActive = true;
			enableAutoReboot = true;
			oxideCheckHoursBack = 168;
		}

        [ConsoleCommand("srestart")]
        void smoothRestartConsoleCommand(ConsoleSystem.Arg arg)
        {
            if(arg.connection != null && arg.connection.authLevel < 2) return;
            if (arg.Args != null && arg.Args.Length == 1)
            {
                if (arg.Args[0].ToLower() == "stop")
				{
					if (countDownActive)
					{
						timerActivated = false;
						secondsActive = false;
						patchRestartRunning = false;
						StopRestart();
						return;
					}
					if (timerActivated)
					{
						timerActivated = false;
						SendReply(arg, StripTags(lang.GetMessage("ManualCancel", this)));
					}
				}
                else
                {
                    int minutes;
                    if (int.TryParse(arg.Args[0], out minutes))
					{
						currentCountDown = Convert.ToInt32(minutes);
						lastMinute = DateTime.Now.Minute;
						timerActivated = true;
						SendReply(arg, StripTags(lang.GetMessage("ManualInit", this)));
					}
                    else
                        SendReply(arg, "Incorrect <minutes> format! Must be number!");
                }
            }
            else
                SendReply(arg, "Incorrect syntax! Must use: srestart <minutes>/stop");
        }
		
        [ChatCommand("srestart")]
        void smoothRestartCommand(BasePlayer player, string command, string[] args)
        {
            if (permission.UserHasPermission(player.UserIDString, "smoothrestart.canrestart") || player.net.connection.authLevel > 1)
            {
                if (args != null && args.Length == 1)
                {
                    if (args[0].ToLower() == "stop")
					{
                        if (countDownActive)
						{
							timerActivated = false;
							secondsActive = false;
							patchRestartRunning = false;
							StopRestart();
							return;
						}
						if (timerActivated)
						{
							timerActivated = false;
							SendReply(player, lang.GetMessage("ManualCancel", this));
						}
					}
                    else
                    {
						int minutes;
						if (int.TryParse(args[0], out minutes))
						{
							currentCountDown = Convert.ToInt32(minutes);
							lastMinute = DateTime.Now.Minute;
							timerActivated = true;
							SendReply(player, lang.GetMessage("ManualInit", this));
						}
                        else
							SendReply(player, "Incorrect <minutes> format! Must be number!");
                    }
                }
                else
                    SendReply(player, "Incorrect syntax! Must use: /srestart <minutes>/stop");
            }
        }

        void StopRestart()
        {
            if (!countDownActive) return;
			countDownActive = false;
			currentCountDown = 0;
			string msg = string.Format(lang.GetMessage("RestartCancel", this));
			Puts(StripTags(msg));
			if(SimpleUI_Enable)
				foreach (BasePlayer player in BasePlayer.activePlayerList)
				{
					UIMessage(player, msg);
				}
			else
				rust.BroadcastChat(msg);
        }		

		void DoSmoothRestart(int timer, bool unitMinutes = true)
        {
			string msg = "";
			if (unitMinutes)
			{
				if (patchRestartRunning)
					msg = string.Format(lang.GetMessage("RestartInitPatch", this), timer);
				else
					msg = string.Format(lang.GetMessage("RestartInit", this), timer);
			}
			else
				msg = string.Format(lang.GetMessage("RestartInitSec", this), timer);
			Puts(StripTags(msg));
			if(SimpleUI_Enable)
				foreach (BasePlayer player in BasePlayer.activePlayerList)
				{
					UIMessage(player, msg);
				}
			else
				rust.BroadcastChat(msg);
        }
		
		class UIColor
        {
            string color;

            public UIColor(double red, double green, double blue, double alpha)
            {
                color = $"{red} {green} {blue} {alpha}";
            }

            public override string ToString() => color;
        }
		
		class UIObject
        {
            List<object> ui = new List<object>();
            List<string> objectList = new List<string>();

            public UIObject()
            {
            }

            string RandomString()
            {
                const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
                List<char> charList = chars.ToList();

                string random = "";

                for (int i = 0; i <= UnityEngine.Random.Range(5, 10); i++)
                    random = random + charList[UnityEngine.Random.Range(0, charList.Count - 1)];

                return random;
            }

            public void Draw(BasePlayer player)
            {
                CommunityEntity.ServerInstance.ClientRPCEx(new Network.SendInfo() { connection = player.net.connection }, null, "AddUI", new Facepunch.ObjectList(JsonConvert.SerializeObject(ui).Replace("{NEWLINE}", Environment.NewLine)));
            }

            public void Destroy(BasePlayer player)
            {
                foreach (string uiName in objectList)
                    CommunityEntity.ServerInstance.ClientRPCEx(new Network.SendInfo() { connection = player.net.connection }, null, "DestroyUI", new Facepunch.ObjectList(uiName));
            }

            public string AddText(string name, double left, double top, double width, double height, UIColor color, string text, int textsize = 15, string parent = "Hud.Under", int alignmode = 0, float fadeIn = 0f, float fadeOut = 0f)
            {
                //name = name + RandomString();
                text = text.Replace("\n", "{NEWLINE}");
                string align = "";

                switch (alignmode)
                {
                    case 0: { align = "LowerCenter"; break; };
                    case 1: { align = "LowerLeft"; break; };
                    case 2: { align = "LowerRight"; break; };
                    case 3: { align = "MiddleCenter"; break; };
                    case 4: { align = "MiddleLeft"; break; };
                    case 5: { align = "MiddleRight"; break; };
                    case 6: { align = "UpperCenter"; break; };
                    case 7: { align = "UpperLeft"; break; };
                    case 8: { align = "UpperRight"; break; };
                }

                ui.Add(new Dictionary<string, object> {
                    {"name", name},
                    {"parent", parent},
                    {"fadeOut", fadeOut.ToString()},
                    {"components",
                        new List<object> {
                            new Dictionary<string, string> {
                                {"type", "UnityEngine.UI.Text"},
                                {"text", text},
                                {"fontSize", textsize.ToString()},
                                {"color", color.ToString()},
                                {"align", align},
                                {"fadeIn", fadeIn.ToString()}
                            },
                            new Dictionary<string, string> {
                                {"type", "RectTransform"},
                                {"anchormin", $"{left} {((1 - top) - height)}"},
                                {"anchormax", $"{(left + width)} {(1 - top)}"}
                            }
                        }
                    }
                });

                objectList.Add(name);
                return name;
            }
        }
		
		void UIMessage(BasePlayer player, string message)
        {
            bool replaced = false;
            float fadeIn = 0.2f;

            Timer playerTimer;

            timers.TryGetValue(player, out playerTimer);

            if (playerTimer != null && !playerTimer.Destroyed)
            {
                playerTimer.Destroy();
                fadeIn = 0.1f;

                replaced = true;
            }

            UIObject ui = new UIObject();

            ui.AddText("DeathNotice_DropShadow", SimpleUI_Left + 0.001, SimpleUI_Top + 0.001, SimpleUI_MaxWidth, SimpleUI_MaxHeight, deathNoticeShadowColor, StripTags(message), SimpleUI_FontSize, "Hud.Under", 3, fadeIn, 0.2f);
            ui.AddText("DeathNotice", SimpleUI_Left, SimpleUI_Top, SimpleUI_MaxWidth, SimpleUI_MaxHeight, deathNoticeColor, message, SimpleUI_FontSize, "Hud.Under", 3, fadeIn, 0.2f);

            ui.Destroy(player);

            if(replaced)
            {
                timer.Once(0.1f, () =>
                {
                    ui.Draw(player);

                    timers[player] = timer.Once(SimpleUI_HideTimer, () => ui.Destroy(player));
                });
            }
            else
            {
                ui.Draw(player);

                timers[player] = timer.Once(SimpleUI_HideTimer, () => ui.Destroy(player));
            }
        }
		
		string StripTags(string original)
        {
            foreach (string tag in tags)
                original = original.Replace(tag, "");

            foreach (Regex regexTag in regexTags)
                original = regexTag.Replace(original, "");

            return original;
        }
	
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху