Skip to content

Commit

Permalink
Support in-game notifications via /notification
Browse files Browse the repository at this point in the history
  • Loading branch information
jvyden committed Oct 3, 2023
1 parent 8e54e78 commit ae8094e
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 51 deletions.
104 changes: 104 additions & 0 deletions Refresh.GameServer/Endpoints/Game/AnnouncementEndpoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System.Text;
using System.Xml.Serialization;
using Bunkum.Core;
using Bunkum.Core.Endpoints;
using Bunkum.Core.Endpoints.Debugging;
using Bunkum.Core.Serialization;
using Bunkum.Listener.Protocol;
using Refresh.GameServer.Authentication;
using Refresh.GameServer.Configuration;
using Refresh.GameServer.Database;
using Refresh.GameServer.Types.Notifications;
using Refresh.GameServer.Types.Roles;
using Refresh.GameServer.Types.UserData;

namespace Refresh.GameServer.Endpoints.Game;

public class AnnouncementEndpoints : EndpointGroup
{
private static string AnnounceGetNotifications(GameDatabaseContext database, GameUser user, GameServerConfig config)
{
List<GameNotification> notifications = database.GetNotificationsByUser(user, 5, 0).Items.ToList();
int count = database.GetNotificationCountByUser(user);
if (count == 0) return string.Empty;

string s = count != 1 ? "s" : string.Empty;

string notificationText = $"Howdy, {user.Username}. You have {count} notification{s}:\n\n";
for (int i = 0; i < notifications.Count; i++)
{
GameNotification notification = notifications[i];
notificationText += $" {notification.Title} ({i + 1}/{count}):\n" +
$" {notification.Text}\n\n";
}

notificationText += $"To view more, or clear these notifications, you can visit the website at {config.WebExternalUrl}!\n";

return notificationText;
}

private static string AnnounceGetAnnouncements(GameDatabaseContext database)
{
IEnumerable<GameAnnouncement> announcements = database.GetAnnouncements();
// it's time to allocate
return announcements.Aggregate(string.Empty, (current, announcement) => current + $"{announcement.Title}: {announcement.Text}\n");
}

[GameEndpoint("announce")]
[MinimumRole(GameUserRole.Restricted)]
public string Announce(RequestContext context, GameServerConfig config, GameUser user, GameDatabaseContext database, Token token)
{
if (user.Role == GameUserRole.Restricted)
{
return "Your account is currently in restricted mode.\n\n" +
"You can still play, but you won't be able to publish levels, post comments," +
"or otherwise interact with the community." +
"For more information, please contact an administrator.";
}

string announcements = AnnounceGetAnnouncements(database);

// All games except PSP support real-time notifications.
// If we're not playing on PSP, move forward to check for notifications.
if (token.TokenGame != TokenGame.LittleBigPlanetPSP) return announcements;

string notifications = AnnounceGetNotifications(database, user, config);

if (announcements.Length == 0) return notifications;
if (notifications.Length == 0) return announcements;
return announcements + "\n" + notifications; // I HATE IT WHYYYYYYYYYYYY
}

[GameEndpoint("notification", ContentType.Xml)]
[MinimumRole(GameUserRole.Restricted)]
[DebugResponseBody]
public string Notification(RequestContext context, GameServerConfig config, GameUser user, GameDatabaseContext database)
{
DatabaseList<GameNotification> notifications = database.GetNotificationsByUser(user, 3, 0);
// ReSharper disable once LoopCanBeConvertedToQuery (makes it unreadable)

using MemoryStream ms = new();
using BunkumXmlTextWriter bunkumXmlTextWriter = new(ms);

XmlSerializer serializer = new(typeof(SerializedNotification));

XmlSerializerNamespaces namespaces = new();
namespaces.Add("", "");

foreach (GameNotification notification in notifications.Items)
{
SerializedNotification serializedNotification = new()
{
Text = $"[{config.InstanceName}] {notification.Title}: {notification.Text}",
};

serializer.Serialize(bunkumXmlTextWriter, serializedNotification, namespaces);
database.DeleteNotification(notification);
}

ms.Seek(0, SeekOrigin.Begin);
using StreamReader reader = new(ms);

return reader.ReadToEnd();
}
}
51 changes: 0 additions & 51 deletions Refresh.GameServer/Endpoints/Game/Handshake/WelcomeEndpoints.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
using Bunkum.Core;
using Bunkum.Core.Endpoints;
using Refresh.GameServer.Configuration;
using Refresh.GameServer.Database;
using Refresh.GameServer.Types.Notifications;
using Refresh.GameServer.Types.Roles;
using Refresh.GameServer.Types.UserData;

namespace Refresh.GameServer.Endpoints.Game.Handshake;

Expand Down Expand Up @@ -33,52 +30,4 @@ public string License(RequestContext context, GameServerConfig config)
{
return config.LicenseText + "\n\n" + AGPLLicense + "\n";
}

private static string AnnounceGetNotifications(GameDatabaseContext database, GameUser user, GameServerConfig config)
{
List<GameNotification> notifications = database.GetNotificationsByUser(user, 5, 0).Items.ToList();
int count = database.GetNotificationCountByUser(user);
if (count == 0) return "";

string s = count != 1 ? "s" : "";

string notificationText = $"Howdy, {user.Username}. You have {count} notification{s}:\n\n";
for (int i = 0; i < notifications.Count; i++)
{
GameNotification notification = notifications[i];
notificationText += $" {notification.Title} ({i + 1}/{count}):\n" +
$" {notification.Text}\n\n";
}

notificationText += $"To view more, or clear these notifications, you can visit the website at {config.WebExternalUrl}!\n";

return notificationText;
}

private static string AnnounceGetAnnouncements(GameDatabaseContext database)
{
IEnumerable<GameAnnouncement> announcements = database.GetAnnouncements();
// it's time to allocate
return announcements.Aggregate("", (current, announcement) => current + $"{announcement.Title}: {announcement.Text}\n");
}

[GameEndpoint("announce")]
[MinimumRole(GameUserRole.Restricted)]
public string Announce(RequestContext context, GameServerConfig config, GameUser user, GameDatabaseContext database)
{
if (user.Role == GameUserRole.Restricted)
{
return "Your account is currently in restricted mode.\n\n" +
"You can still play, but you won't be able to publish levels, post comments," +
"or otherwise interact with the community." +
"For more information, please contact an administrator.";
}

string announcements = AnnounceGetAnnouncements(database);
string notifications = AnnounceGetNotifications(database, user, config);

if (announcements.Length == 0) return notifications;
if (notifications.Length == 0) return announcements;
return announcements + "\n" + notifications; // I HATE IT WHYYYYYYYYYYYY
}
}
5 changes: 5 additions & 0 deletions Refresh.GameServer/RefreshGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Bunkum.Core.Authentication;
using Bunkum.Core.Configuration;
using Bunkum.Core.RateLimit;
using Bunkum.Core.Services;
using Bunkum.Core.Storage;
using Bunkum.HealthChecks;
using Bunkum.Protocols.Http;
Expand Down Expand Up @@ -149,6 +150,10 @@ protected virtual void SetupServices()

if (this._config!.TrackRequestStatistics)
this._server.AddService<RequestStatisticTrackingService>();

#if DEBUG
this._server.AddService<DebugService>();
#endif
}

protected virtual void SetupWorkers()
Expand Down
13 changes: 13 additions & 0 deletions Refresh.GameServer/Types/Notifications/SerializedNotification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Xml.Serialization;

namespace Refresh.GameServer.Types.Notifications;

#nullable disable

[XmlType("notification")]
[XmlRoot("notification")]
public class SerializedNotification
{
[XmlAttribute("type")] public string Type { get; set; } = "moderationNotification";
[XmlElement("text")] public string Text { get; set; }
}

0 comments on commit ae8094e

Please sign in to comment.