From 65eeb7dd535f7c99b465fe117b20ce5eb1fe22a7 Mon Sep 17 00:00:00 2001 From: Hipposgrumm <60556345+Hipposgrumm@users.noreply.github.com> Date: Wed, 10 Jul 2024 03:14:09 -0600 Subject: [PATCH] Added support for Red Alert and Disco Alert (#3) Revamped entire room Alerts system. Merged RoomWithAlert into Room (as part of the revamp). This added support for Red Alert and Disco Alert. This meant that I had to revamp the room alerts system to allow for multiple alerts per room. Events hopefully shouldn't overlap each other in the same room. An extra feature is that an alert will start for a player that has just entered the room (with a duration reduced based on when the alert initially started). I shoved this functionality's working into SetUserVariablesHandler on line 30. This feature doesn't seem to work when leaving a non-MMO rooms such as minigames (may be related to missed JL command). --- .../SetUserVariablesHandler.cs | 1 + src/Core/Room.cs | 133 ++++++++++++++++++ src/Core/RoomWithAlert.cs | 48 ------- src/Server.cs | 5 +- 4 files changed, 138 insertions(+), 49 deletions(-) delete mode 100644 src/Core/RoomWithAlert.cs diff --git a/src/CommandHandlers/SetUserVariablesHandler.cs b/src/CommandHandlers/SetUserVariablesHandler.cs index 878a32a..3665551 100644 --- a/src/CommandHandlers/SetUserVariablesHandler.cs +++ b/src/CommandHandlers/SetUserVariablesHandler.cs @@ -27,6 +27,7 @@ class SetUserVariablesHandler : CommandHandler { client.PlayerData.InitFromNetworkData(suvData); UpdatePlayersInRoom(); SendSUVToPlayerInRoom(); + client.Room.SendAllAlerts(client); } else { UpdateVars(); } diff --git a/src/Core/Room.cs b/src/Core/Room.cs index 15916f6..4d683ab 100644 --- a/src/Core/Room.cs +++ b/src/Core/Room.cs @@ -153,4 +153,137 @@ public class Room { obj.Add("g", Group); return NetworkObject.WrapObject(0, 15, obj).Serialize(); } + + + private int alertId = -1; + private Random random = new Random(); + + List alerts = new(); + + public void AddAlert(AlertInfo alert) { + alerts.Add(alert); + ResetAlertTimer(alert); + } + + public void SendAllAlerts(Client client) { + foreach (AlertInfo alert in alerts) { + if (alert.IsRunning()) StartAlert(alert, client); + } + } + + + private void StartAlert(AlertInfo alert, Client? specificClient = null) { + alert.songId = random.Next(0, alert.songs); + NetworkArray NewRoomVariables = new(); + NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_START, alertId++, isPersistent: true)); + NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_TYPE, alert.type, isPersistent: true)); + double duration = (alert.endTime - DateTime.Now).TotalSeconds; + NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_LENGTH, alert.type == "1" ? alert.redAlertDuration : duration, isPersistent: true)); + if (alert.type == "1") NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_TIMEOUT, duration, isPersistent: true)); + if (alert.type == "3") NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_SONG, (double)alert.songId, isPersistent: true)); + NetworkPacket packet = Utils.VlNetworkPacket(NewRoomVariables, Id); + if (specificClient is null) { + RoomVariables = NewRoomVariables; + Send(packet); + Console.WriteLine("Started event " +alert + " in room " + Name); + } else { + specificClient.Send(packet); + Console.WriteLine("Added " + specificClient.PlayerData.DiplayName + " to event " + alert + " with " + duration + " seconds remaining"); + } + } + + void ResetAlertTimer(AlertInfo alert) { + System.Timers.Timer? timer = alert.timer; + if (timer != null) { + timer.Stop(); + timer.Close(); + } + DateTime startTime = DateTime.Now.AddMilliseconds(random.Next(alert.minTime * 1000, alert.maxTime * 1000)); + DateTime endTime = startTime.AddSeconds(alert.duration); + for (int i = 0; i < alerts.IndexOf(alert); i++) { + // Prevent overlap between two events. + if (alerts[i].Overlaps(endTime)) { + startTime = alerts[i].endTime.AddSeconds(5); + endTime = startTime.AddSeconds(alert.duration); + } + } + timer = new System.Timers.Timer((startTime - DateTime.Now).TotalMilliseconds); + timer.AutoReset = false; + timer.Enabled = true; + timer.Elapsed += (sender, e) => StartAlert(alert); + timer.Elapsed += (sender, e) => ResetAlertTimer(alert); + alert.timer = timer; + Console.WriteLine("Event " + alert + " in " + Name + " scheduled for " + startTime.ToString("MM/dd/yyyy HH:mm:ss tt") + " (in " + (startTime - DateTime.Now).TotalSeconds + " seconds)"); + alert.startTime = startTime; + alert.endTime = endTime; + } + + private const string REDALERT_START = "RA_S"; + private const string REDALERT_TYPE = "RA_A"; + private const string REDALERT_LENGTH = "RA_L"; + private const string REDALERT_TIMEOUT = "RA_T"; + private const string REDALERT_SONG = "RA_SO"; + + public class AlertInfo { + public readonly string type; + public readonly double duration; + public readonly int minTime; + public readonly int maxTime; + public readonly int redAlertDuration; + public readonly int songs; + public int songId; + + public DateTime startTime { + get { + return newStartTime; + } + set { + oldStartTime = newStartTime; + newStartTime = value; + } + } + + public DateTime endTime { + get { + return newEndTime; + } + set { + oldEndTime = newEndTime; + newEndTime = value; + } + } + + private DateTime newStartTime; + private DateTime newEndTime; + private DateTime oldStartTime; + private DateTime oldEndTime; + + public System.Timers.Timer? timer = null; + + public AlertInfo(string type, double duration = 20.0, int minTime = 30, int maxTime = 240, int redAlertDuration = 60, int songs = 16) { + this.type = type; + this.duration = duration; + this.minTime = minTime; + this.maxTime = maxTime; + this.redAlertDuration = redAlertDuration; + this.songs = songs; + } + + public bool Overlaps(DateTime time) { + return (time >= oldStartTime && time <= oldEndTime); + } + + public bool IsRunning() { + return Overlaps(DateTime.Now); + } + + public override string ToString() { + return type switch { + "1" => "RedAlert", + "2" => "DiscoAlert", + "3" => "DanceOff", + _ => type + }; + } + } } diff --git a/src/Core/RoomWithAlert.cs b/src/Core/RoomWithAlert.cs deleted file mode 100644 index 9023635..0000000 --- a/src/Core/RoomWithAlert.cs +++ /dev/null @@ -1,48 +0,0 @@ -using sodoffmmo.Data; -using System.Timers; - -namespace sodoffmmo.Core; -class RoomWithAlert : Room { - private int alertId; - private System.Timers.Timer? timer = null; - private Random random = new Random(); - - private int minTime; - private int maxTime; - private int songs; - - public RoomWithAlert(string name, int minTime = 30, int maxTime = 240, int songs = 16) : base (name) { - alertId = -1; - - this.minTime = minTime; - this.maxTime = maxTime; - this.songs = songs; - - SetTimer(); - } - - private void StartAlert(Object? source, ElapsedEventArgs e) { - int songId = random.Next(0, songs); - RoomVariables = new(); - RoomVariables.Add(NetworkArray.VlElement("RA_S", ++alertId, isPersistent: true)); - RoomVariables.Add(NetworkArray.VlElement("RA_A", "3", isPersistent: true)); - RoomVariables.Add(NetworkArray.VlElement("RA_L", 20.0, isPersistent: true)); - RoomVariables.Add(NetworkArray.VlElement("RA_SO", (double)songId, isPersistent: true)); - NetworkPacket packet = Utils.VlNetworkPacket(RoomVariables, Id); - Send(packet); - SetTimer(); - } - - private void SetTimer() { - if (timer != null) { - timer.Stop(); - timer.Close(); - } - timer = new System.Timers.Timer( - random.Next(minTime * 1000, maxTime * 1000) - ); - timer.AutoReset = false; - timer.Enabled = true; - timer.Elapsed += StartAlert; - } -} diff --git a/src/Server.cs b/src/Server.cs index 7c3c600..9a46352 100644 --- a/src/Server.cs +++ b/src/Server.cs @@ -28,7 +28,10 @@ public class Server { if (IPv6AndIPv4) listener.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0); listener.Bind(new IPEndPoint(ipAddress, port)); - new RoomWithAlert("LoungeInt"); // FIXME use config for this + Room.GetOrAdd("LoungeInt").AddAlert(new Room.AlertInfo("3")); // FIXME use config for this + Room.GetOrAdd("Spaceport").AddAlert(new Room.AlertInfo("1", 20.0, 300, 300)); + Room.GetOrAdd("Spaceport").AddAlert(new Room.AlertInfo("2", 120.0, 1800, 3600)); + Room.GetOrAdd("Academy").AddAlert(new Room.AlertInfo("1", 20.0, 300, 300)); await Listen(listener); }