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); }