using Oxide.Core.Plugins; using Oxide.Core; using System; using System.Text; using System.Collections.Generic; using System.Globalization; using UnityEngine; namespace Oxide.Plugins { [Info("TimeOfDay", "u-channel", "1.3.0")] [Description("昼と夜の長さ、日時固定、自動スキップを設定できるプラグインです。")] public class TimeOfDay : RustPlugin { bool Changed; bool Initialized; int componentSearchAttempts; TOD_Time timeComponent; bool activatedDay; int authLevelCmds; int authLevelFreeze; int dayLength; int nightLength; int presetDay; int presetMonth; int presetYear; bool setPresetDate; bool freezeDate; bool autoSkipNight; bool autoSkipDay; bool logAutoSkipConsole; bool freezeTimeOnload; float timeToFreeze; object GetConfig(string menu, string datavalue, string description, object defaultValue) { var data = Config[menu] as Dictionary; if (data == null) { data = new Dictionary(); Config[menu] = data; Changed = true; } object entry; if (!data.TryGetValue(datavalue, out entry)) { data[datavalue] = new Dictionary { { "説明", description }, { "値", defaultValue } }; Changed = true; return defaultValue; } var setting = entry as Dictionary; if (setting == null) { // 旧形式(直接値のみ)から、日本語説明付き形式へ自動変換します。 data[datavalue] = new Dictionary { { "説明", description }, { "値", entry } }; Changed = true; return entry; } if (!setting.ContainsKey("説明")) { setting["説明"] = description; Changed = true; } if (!setting.ContainsKey("値")) { setting["値"] = defaultValue; Changed = true; } return setting["値"]; } void SetConfigValue(string menu, string datavalue, string description, object value) { var data = Config[menu] as Dictionary; if (data == null) { data = new Dictionary(); Config[menu] = data; } data[datavalue] = new Dictionary { { "説明", description }, { "値", value } }; } void LoadVariables() { dayLength = System.Convert.ToInt32(GetConfig("Settings", "dayLength", "昼の長さを分単位で指定します。例:30なら昼が現実時間で30分になります。", 30)); nightLength = System.Convert.ToInt32(GetConfig("Settings", "nightLength", "夜の長さを分単位で指定します。例:30なら夜が現実時間で30分になります。", 30)); freezeDate = System.Convert.ToBoolean(GetConfig("Settings", "freezeDate", "trueにするとゲーム内の日付を固定します。時間は進みますが日付が進まないようにします。", false)); authLevelCmds = System.Convert.ToInt32(GetConfig("Settings", "authLevelCmds", "昼夜の長さ変更や昼夜スキップ系コマンドに必要な管理者権限レベルです。", 1)); authLevelFreeze = System.Convert.ToInt32(GetConfig("Settings", "authLevelFreeze", "時間停止コマンド tod.freezetime に必要な管理者権限権限レベルです。", 2)); autoSkipNight = System.Convert.ToBoolean(GetConfig("Settings", "autoSkipNight", "trueにすると夜になった時点で自動的に朝までスキップします。", false)); autoSkipDay = System.Convert.ToBoolean(GetConfig("Settings", "autoSkipDay", "trueにすると昼になった時点で自動的に夕方までスキップします。autoSkipNightと同時にtrueにしないでください。", false)); logAutoSkipConsole = System.Convert.ToBoolean(GetConfig("Settings", "logAutoSkipConsole", "自動スキップが実行された時にサーバーコンソールへログを出すかどうかです。", true)); presetDay = System.Convert.ToInt32(GetConfig("DatePreset", "presetDay", "下記のsetPresetDateがtrueの時、サーバー初期化時にこの日付からスタートします。", 1)); presetMonth = System.Convert.ToInt32(GetConfig("DatePreset", "presetMonth", "下記のsetPresetDateがtrueの時、サーバー初期化時にこの月からスタートします。", 1)); presetYear = System.Convert.ToInt32(GetConfig("DatePreset", "presetYear", "下記のsetPresetDateがtrueの時、サーバー初期化時にこの西暦からスタートします。", 2020)); setPresetDate = System.Convert.ToBoolean(GetConfig("DatePreset", "setPresetDate", "trueにするとサーバー初期化時に presetDay / presetMonth / presetYear の日付へ変更します。", false)); freezeTimeOnload = System.Convert.ToBoolean(GetConfig("TimeFreeze", "freezeTimeOnload", "trueにするとプラグイン読み込み時に時間を停止します。", false)); timeToFreeze = System.Convert.ToSingle(GetConfig("TimeFreeze", "timeToFreeze", "freezeTimeOnloadがtrueの時に固定するゲーム内時刻です。0〜24の数値で指定します。例:12.0なら正午です。", 12.0)); if (!Changed) return; SaveConfig(); Changed = false; } protected override void LoadDefaultConfig() { Config.Clear(); LoadVariables(); } void Loaded() { LoadVariables(); Initialized = false; } void Unload() { if (timeComponent == null || !Initialized) return; timeComponent.OnSunrise -= OnSunrise; timeComponent.OnSunset -= OnSunset; timeComponent.OnDay -= OnDay; timeComponent.OnHour -= OnHour; } void OnServerInitialized() { if (TOD_Sky.Instance == null) { componentSearchAttempts++; if (componentSearchAttempts < 10) timer.Once(1, OnServerInitialized); else PrintWarning("Could not find required component after 10 attempts. Plugin disabled"); return; } timeComponent = TOD_Sky.Instance.Components.Time; if (timeComponent == null) { PrintWarning("Could not fetch time component. Plugin disabled"); return; } if (setPresetDate) { TOD_Sky.Instance.Cycle.Day = presetDay; TOD_Sky.Instance.Cycle.Month = presetMonth; TOD_Sky.Instance.Cycle.Year = presetYear; } SetTimeComponent(); if (freezeTimeOnload) StartupFreeze(); } void SetTimeComponent() { timeComponent.ProgressTime = true; timeComponent.UseTimeCurve = false; timeComponent.OnSunrise += OnSunrise; timeComponent.OnSunset += OnSunset; timeComponent.OnDay += OnDay; timeComponent.OnHour += OnHour; Initialized = true; if (TOD_Sky.Instance.Cycle.Hour > TOD_Sky.Instance.SunriseTime && TOD_Sky.Instance.Cycle.Hour < TOD_Sky.Instance.SunsetTime) OnSunrise(); else OnSunset(); } void StartupFreeze() { if (!Initialized) return; timeComponent.ProgressTime = false; ConVar.Env.time = timeToFreeze; } void OnDay() { if (Initialized && freezeDate) --TOD_Sky.Instance.Cycle.Day; } void OnHour() { if (!Initialized) return; if (TOD_Sky.Instance.Cycle.Hour > TOD_Sky.Instance.SunriseTime && TOD_Sky.Instance.Cycle.Hour < TOD_Sky.Instance.SunsetTime && !activatedDay) { OnSunrise(); return; } if ((TOD_Sky.Instance.Cycle.Hour > TOD_Sky.Instance.SunsetTime || TOD_Sky.Instance.Cycle.Hour < TOD_Sky.Instance.SunriseTime) && activatedDay) { OnSunset(); return; } } void OnSunrise() { if (!Initialized) return; if (autoSkipDay && !autoSkipNight) { TOD_Sky.Instance.Cycle.Hour = TOD_Sky.Instance.SunsetTime; if (logAutoSkipConsole) Puts("Daytime autoskipped"); OnSunset(); return; } timeComponent.DayLengthInMinutes = dayLength * (24.0f / (TOD_Sky.Instance.SunsetTime - TOD_Sky.Instance.SunriseTime)); if (!activatedDay) Interface.CallHook("OnTimeSunrise"); activatedDay = true; } void OnSunset() { if (!Initialized) return; if (autoSkipNight) { float timeToAdd = (24 - TOD_Sky.Instance.Cycle.Hour) + TOD_Sky.Instance.SunriseTime; TOD_Sky.Instance.Cycle.Hour += timeToAdd; if (logAutoSkipConsole) Puts("Nighttime autoskipped"); OnSunrise(); return; } timeComponent.DayLengthInMinutes = nightLength * (24.0f / (24.0f - (TOD_Sky.Instance.SunsetTime - TOD_Sky.Instance.SunriseTime))); if (activatedDay) Interface.CallHook("OnTimeSunset"); activatedDay = false; } [ConsoleCommand("tod.daylength")] void ConsoleDayLength(ConsoleSystem.Arg arg) { if (!Initialized) return; if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return; if (arg.Args == null || arg.Args.Length < 1) { SendReply(arg, $"Current 'dayLength' setting is '{dayLength}'"); return; } int newDaylength = 0; if (int.TryParse(arg.Args[0], out newDaylength)) { if (newDaylength < 1) { SendReply(arg, $"The new daylength must be greater zero"); return; } } dayLength = newDaylength; SendReply(arg, $"The 'dayLength' has been set to '{dayLength}'"); if (TOD_Sky.Instance.IsDay) OnSunrise(); else OnSunset(); SetConfigValue("Settings", "dayLength", "昼の長さを分単位で指定します。例:30なら昼が30分になります。", dayLength); SaveConfig(); } [ConsoleCommand("tod.nightlength")] void ConsoleNightLength(ConsoleSystem.Arg arg) { if (!Initialized) return; if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return; if (arg.Args == null || arg.Args.Length < 1) { SendReply(arg, $"Current 'nightLength' setting is '{nightLength}'"); return; } int newNightlength = 0; if (int.TryParse(arg.Args[0], out newNightlength)) { if (newNightlength < 1) { SendReply(arg, $"The new nightlength must be greater zero"); return; } } nightLength = newNightlength; SendReply(arg, $"The 'nightLength' has been set to '{nightLength}'"); if (TOD_Sky.Instance.IsDay) OnSunrise(); else OnSunset(); SetConfigValue("Settings", "nightLength", "夜の長さを分単位で指定します。例:30なら夜が30分になります。", nightLength); SaveConfig(); } [ConsoleCommand("tod.freezetime")] void ConsoleFreezeTime(ConsoleSystem.Arg arg) { if (!Initialized) return; if (arg.Connection != null && arg.Connection.authLevel < authLevelFreeze) return; timeComponent.ProgressTime = !timeComponent.ProgressTime; if (timeComponent.ProgressTime) SendReply(arg, $"The game time was unfreezed"); else SendReply(arg, $"The game time was freezed"); } [ConsoleCommand("tod.skipday")] void ConsoleSkipDay(ConsoleSystem.Arg arg) { if (!Initialized) return; if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return; if (TOD_Sky.Instance.IsNight) { SendReply(arg, $"Night is already active"); return; } OnSunset(); TOD_Sky.Instance.Cycle.Hour = TOD_Sky.Instance.SunsetTime; SendReply(arg, $"Current daytime skipped"); } [ConsoleCommand("tod.skipnight")] void ConsoleSkipNight(ConsoleSystem.Arg arg) { if (!Initialized) return; if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return; if (TOD_Sky.Instance.IsDay) { SendReply(arg, $"Day is already active"); return; } OnSunrise(); TOD_Sky.Instance.Cycle.Hour = TOD_Sky.Instance.SunriseTime; SendReply(arg, $"Current nighttime skipped"); } [ChatCommand("tod")] private void TodCommand(BasePlayer player, string command, string[] args) { if (!Initialized) return; TimeSpan ts1= TimeSpan.FromHours(TOD_Sky.Instance.SunriseTime); TimeSpan ts2= TimeSpan.FromHours(TOD_Sky.Instance.SunsetTime); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(FormNeutralMessage("-------- Settings --------")); stringBuilder.AppendLine("Current Time".PadRight(15) + TOD_Sky.Instance.Cycle.DateTime.ToString("HH:mm:ss")); stringBuilder.AppendLine("Sunrise Hour".PadRight(15) + string.Format("{0}:{1}", System.Math.Truncate(ts1.TotalHours).ToString(), ts1.Minutes.ToString())); stringBuilder.AppendLine("Sunset Hour".PadRight(15) + string.Format("{0}:{1}", System.Math.Truncate(ts2.TotalHours).ToString(), ts2.Minutes.ToString())); stringBuilder.AppendLine("Daylength".PadRight(15) + dayLength.ToString() + " minutes"); stringBuilder.Append("Nightlength".PadRight(15) + nightLength.ToString() + " minutes"); PrintPluginMessageToChat(player, stringBuilder.ToString().TrimEnd()); } [HookMethod("SendHelpText")] private void SendHelpText(BasePlayer player) { if (!Initialized) return; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(FormNeutralMessage("-------------------- Available Commands --------------------\n")); stringBuilder.Append(FormNeutralMessage("/tod") + " - Shows current Time Of Day.\n"); PrintPluginMessageToChat(player, stringBuilder.ToString()); } private void PrintPluginMessageToChat(BasePlayer player, string message) { PrintToChat(player, "[" + this.Name + "]\n" + message); } private void PrintPluginMessageToChat(string message) { PrintToChat("[" + this.Name + "]\n" + message); } private string FormNeutralMessage(string message) { return "" + message + ""; } } }