Convert rules to use guidebook parsing (#28647)

This commit is contained in:
Nemanja
2024-06-06 03:11:26 -04:00
committed by GitHub
parent 8b40d1887c
commit 1333b48747
33 changed files with 4035 additions and 413 deletions

View File

@@ -2,11 +2,9 @@ using Content.Client.Administration.Managers;
using Content.Client.Changelog;
using Content.Client.Chat.Managers;
using Content.Client.Eui;
using Content.Client.Flash;
using Content.Client.Fullscreen;
using Content.Client.GhostKick;
using Content.Client.Guidebook;
using Content.Client.Info;
using Content.Client.Input;
using Content.Client.IoC;
using Content.Client.Launcher;
@@ -52,7 +50,6 @@ namespace Content.Client.Entry
[Dependency] private readonly IScreenshotHook _screenshotHook = default!;
[Dependency] private readonly FullscreenHook _fullscreenHook = default!;
[Dependency] private readonly ChangelogManager _changelogManager = default!;
[Dependency] private readonly RulesManager _rulesManager = default!;
[Dependency] private readonly ViewportManager _viewportManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
@@ -125,7 +122,6 @@ namespace Content.Client.Entry
_screenshotHook.Initialize();
_fullscreenHook.Initialize();
_changelogManager.Initialize();
_rulesManager.Initialize();
_viewportManager.Initialize();
_ghostKick.Initialize();
_extendedDisconnectInformation.Initialize();

View File

@@ -2,6 +2,8 @@ using System.Linq;
using Content.Client.Guidebook.Richtext;
using Pidgin;
using Robust.Client.UserInterface;
using Robust.Shared.ContentPack;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
using Robust.Shared.Sandboxing;
using static Pidgin.Parser;
@@ -13,7 +15,9 @@ namespace Content.Client.Guidebook;
/// </summary>
public sealed partial class DocumentParsingManager
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly ISandboxHelper _sandboxHelper = default!;
private readonly Dictionary<string, Parser<char, Control>> _tagControlParsers = new();
@@ -37,6 +41,21 @@ public sealed partial class DocumentParsingManager
ControlParser = SkipWhitespaces.Then(_controlParser.Many());
}
public bool TryAddMarkup(Control control, ProtoId<GuideEntryPrototype> entryId, bool log = true)
{
if (!_prototype.TryIndex(entryId, out var entry))
return false;
using var file = _resourceManager.ContentFileReadText(entry.Text);
return TryAddMarkup(control, file.ReadToEnd(), log);
}
public bool TryAddMarkup(Control control, GuideEntry entry, bool log = true)
{
using var file = _resourceManager.ContentFileReadText(entry.Text);
return TryAddMarkup(control, file.ReadToEnd(), log);
}
public bool TryAddMarkup(Control control, string text, bool log = true)
{
try

View File

@@ -1,25 +0,0 @@
using Content.Shared.Info;
using Robust.Shared.Log;
namespace Content.Client.Info;
public sealed class InfoSystem : EntitySystem
{
public RulesMessage Rules = new RulesMessage("Server Rules", "The server did not send any rules.");
[Dependency] private readonly RulesManager _rules = default!;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<RulesMessage>(OnRulesReceived);
Log.Debug("Requested server info.");
RaiseNetworkEvent(new RequestRulesMessage());
}
private void OnRulesReceived(RulesMessage message, EntitySessionEventArgs eventArgs)
{
Log.Debug("Received server rules.");
Rules = message;
_rules.UpdateRules();
}
}

View File

@@ -1,10 +1,8 @@
using System.Numerics;
using Content.Client.UserInterface.Systems.EscapeMenu;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
namespace Content.Client.Info
@@ -12,7 +10,6 @@ namespace Content.Client.Info
public sealed class RulesAndInfoWindow : DefaultWindow
{
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly RulesManager _rules = default!;
public RulesAndInfoWindow()
{
@@ -22,8 +19,14 @@ namespace Content.Client.Info
var rootContainer = new TabContainer();
var rulesList = new Info();
var tutorialList = new Info();
var rulesList = new RulesControl
{
Margin = new Thickness(10)
};
var tutorialList = new Info
{
Margin = new Thickness(10)
};
rootContainer.AddChild(rulesList);
rootContainer.AddChild(tutorialList);
@@ -31,7 +34,6 @@ namespace Content.Client.Info
TabContainer.SetTabTitle(rulesList, Loc.GetString("ui-info-tab-rules"));
TabContainer.SetTabTitle(tutorialList, Loc.GetString("ui-info-tab-tutorial"));
AddSection(rulesList, _rules.RulesSection());
PopulateTutorial(tutorialList);
Contents.AddChild(rootContainer);

View File

@@ -1,6 +1,18 @@
<BoxContainer xmlns="https://spacestation14.io"
Name="InfoContainer"
Orientation="Vertical"
Margin="2 2 0 0"
SeparationOverride="10"
Access="Public"/>
<BoxContainer xmlns="https://spacestation14.io" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<Control HorizontalExpand="True" VerticalExpand="True" HorizontalAlignment="Stretch">
<ScrollContainer Name="Scroll" HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Name="RulesContainer" VerticalExpand="True" Margin="0 0 5 0"/>
</ScrollContainer>
<BoxContainer Margin="0 0 15 0" HorizontalExpand="True" HorizontalAlignment="Right">
<Button Name="BackButton"
Text="{Loc 'ui-rules-button-back'}"
HorizontalAlignment="Right"
VerticalAlignment="Top"/>
<Control MinWidth="5"/>
<Button Name="HomeButton"
Text="{Loc 'ui-rules-button-home'}"
HorizontalAlignment="Right"
VerticalAlignment="Top"/>
</BoxContainer>
</Control>
</BoxContainer>

View File

@@ -1,22 +1,53 @@
using System.IO;
using Content.Shared.CCVar;
using Content.Client.Guidebook;
using Content.Client.Guidebook.RichText;
using Content.Client.UserInterface.Systems.Info;
using Robust.Client.AutoGenerated;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
namespace Content.Client.Info;
[GenerateTypedNameReferences]
public sealed partial class RulesControl : BoxContainer
public sealed partial class RulesControl : BoxContainer, ILinkClickHandler
{
[Dependency] private readonly RulesManager _rules = default!;
[Dependency] private readonly DocumentParsingManager _parsingMan = default!;
private string? _currentEntry;
private readonly Stack<string> _priorEntries = new();
public RulesControl()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
AddChild(_rules.RulesSection());
SetGuide();
HomeButton.OnPressed += _ => SetGuide();
BackButton.OnPressed += _ => SetGuide(_priorEntries.Pop(), false);
}
public void HandleClick(string link)
{
SetGuide(link);
}
private void SetGuide(ProtoId<GuideEntryPrototype>? entry = null, bool addToPrior = true)
{
var coreEntry = UserInterfaceManager.GetUIController<InfoUIController>().GetCoreRuleEntry();
entry ??= coreEntry;
Scroll.SetScrollValue(default);
RulesContainer.Children.Clear();
if (!_parsingMan.TryAddMarkup(RulesContainer, entry.Value))
return;
if (addToPrior && _currentEntry != null)
_priorEntries.Push(_currentEntry);
_currentEntry = entry.Value;
HomeButton.Visible = entry.Value != coreEntry.Id;
BackButton.Visible = _priorEntries.Count != 0 && _priorEntries.Peek() != entry.Value;
}
}

View File

@@ -1,105 +0,0 @@
using Content.Client.Lobby;
using Content.Client.Gameplay;
using Content.Shared.CCVar;
using Content.Shared.Info;
using Robust.Client.Console;
using Robust.Client.State;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
namespace Content.Client.Info;
public sealed class RulesManager : SharedRulesManager
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
private InfoSection rulesSection = new InfoSection("", "", false);
private bool _shouldShowRules = false;
private RulesPopup? _activePopup;
public void Initialize()
{
_netManager.RegisterNetMessage<ShouldShowRulesPopupMessage>(OnShouldShowRules);
_netManager.RegisterNetMessage<ShowRulesPopupMessage>(OnShowRulesPopupMessage);
_netManager.RegisterNetMessage<RulesAcceptedMessage>();
_stateManager.OnStateChanged += OnStateChanged;
_consoleHost.RegisterCommand("fuckrules", "", "", (_, _, _) =>
{
OnAcceptPressed();
});
}
private void OnShouldShowRules(ShouldShowRulesPopupMessage message)
{
_shouldShowRules = true;
}
private void OnShowRulesPopupMessage(ShowRulesPopupMessage message)
{
ShowRules(message.PopupTime);
}
private void OnStateChanged(StateChangedEventArgs args)
{
if (args.NewState is not (GameplayState or LobbyState))
return;
if (!_shouldShowRules)
return;
_shouldShowRules = false;
ShowRules(_configManager.GetCVar(CCVars.RulesWaitTime));
}
private void ShowRules(float time)
{
if (_activePopup != null)
return;
_activePopup = new RulesPopup
{
Timer = time
};
_activePopup.OnQuitPressed += OnQuitPressed;
_activePopup.OnAcceptPressed += OnAcceptPressed;
_userInterfaceManager.WindowRoot.AddChild(_activePopup);
LayoutContainer.SetAnchorPreset(_activePopup, LayoutContainer.LayoutPreset.Wide);
}
private void OnQuitPressed()
{
_consoleHost.ExecuteCommand("quit");
}
private void OnAcceptPressed()
{
_netManager.ClientSendMessage(new RulesAcceptedMessage());
_activePopup?.Orphan();
_activePopup = null;
}
public void UpdateRules()
{
var rules = _sysMan.GetEntitySystem<InfoSystem>().Rules;
rulesSection.SetText(rules.Title, rules.Text, true);
}
public Control RulesSection()
{
rulesSection = new InfoSection("", "", false);
UpdateRules();
return rulesSection;
}
}

View File

@@ -5,20 +5,20 @@
MouseFilter="Stop">
<parallax:ParallaxControl />
<Control VerticalExpand="True"
MaxWidth="650">
MaxWidth="800"
MaxHeight="900">
<PanelContainer StyleClasses="windowPanel" />
<ScrollContainer HScrollEnabled="False">
<BoxContainer Orientation="Vertical" SeparationOverride="10">
<info:RulesControl />
<BoxContainer Orientation="Vertical" SeparationOverride="10" Margin="10 10 5 10">
<info:RulesControl/>
<Label Name="WaitLabel" />
<BoxContainer Orientation="Horizontal">
<Button Name="AcceptButton"
Text="{Loc 'ui-rules-accept'}"
Disabled="True" />
<Button Name="QuitButton"
StyleClasses="Caution"
Text="{Loc 'ui-escape-quit'}" />
</BoxContainer>
</BoxContainer>
</ScrollContainer>
</Control>
</Control>

View File

@@ -1,9 +1,7 @@
using System;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;
using Robust.Shared.Timing;
namespace Content.Client.Info;

View File

@@ -4,7 +4,6 @@ using Content.Client.Chat.Managers;
using Content.Client.Clickable;
using Content.Client.Eui;
using Content.Client.GhostKick;
using Content.Client.Info;
using Content.Client.Launcher;
using Content.Client.Parallax.Managers;
using Content.Client.Players.PlayTimeTracking;
@@ -41,7 +40,6 @@ namespace Content.Client.IoC
collection.Register<EuiManager, EuiManager>();
collection.Register<IVoteManager, VoteManager>();
collection.Register<ChangelogManager, ChangelogManager>();
collection.Register<RulesManager, RulesManager>();
collection.Register<ViewportManager, ViewportManager>();
collection.Register<ISharedAdminLogManager, SharedAdminLogManager>();
collection.Register<GhostKickManager>();

View File

@@ -1,13 +1,73 @@
using Content.Client.Gameplay;
using System.Globalization;
using Content.Client.Gameplay;
using Content.Client.Guidebook;
using Content.Client.Info;
using Content.Shared.Administration.Managers;
using Content.Shared.CCVar;
using Content.Shared.Info;
using Robust.Client;
using Robust.Client.Console;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.Systems.Info;
public sealed class InfoUIController : UIController, IOnStateExited<GameplayState>
{
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly ISharedAdminManager _adminManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
private RulesPopup? _rulesPopup;
private RulesAndInfoWindow? _infoWindow;
private static DateTime NextRulesReadTime => DateTime.UtcNow + TimeSpan.FromDays(60);
public override void Initialize()
{
base.Initialize();
_client.PlayerJoinedServer += OnJoinedServer;
_netManager.RegisterNetMessage<ShowRulesPopupMessage>(OnShowRulesPopupMessage);
_consoleHost.RegisterCommand("fuckrules",
"",
"",
(_, _, _) =>
{
OnAcceptPressed();
});
}
private void OnJoinedServer(object? sender, PlayerEventArgs args)
{
if (_playerManager.LocalSession is not { } localSession)
return;
if (_adminManager.IsAdmin(localSession) && _cfg.GetCVar(CCVars.RulesExemptLocal))
return;
var nextReadTarget = DateTime.Parse(_cfg.GetCVar(CCVars.RulesNextPopupTime));
if (nextReadTarget >= DateTime.UtcNow)
return;
var time = _cfg.GetCVar(CCVars.RulesWaitTime);
ShowRules(time);
}
private void OnShowRulesPopupMessage(ShowRulesPopupMessage message)
{
ShowRules(message.PopupTime);
}
public void OnStateExited(GameplayState state)
{
if (_infoWindow == null)
@@ -17,12 +77,47 @@ public sealed class InfoUIController : UIController, IOnStateExited<GameplayStat
_infoWindow = null;
}
private void ShowRules(float time)
{
if (_rulesPopup != null)
return;
_rulesPopup = new RulesPopup
{
Timer = time
};
_rulesPopup.OnQuitPressed += OnQuitPressed;
_rulesPopup.OnAcceptPressed += OnAcceptPressed;
UIManager.WindowRoot.AddChild(_rulesPopup);
LayoutContainer.SetAnchorPreset(_rulesPopup, LayoutContainer.LayoutPreset.Wide);
}
private void OnQuitPressed()
{
_consoleHost.ExecuteCommand("quit");
}
private void OnAcceptPressed()
{
_cfg.SetCVar(CCVars.RulesNextPopupTime, NextRulesReadTime.ToString(CultureInfo.InvariantCulture));
_cfg.SaveToFile();
_rulesPopup?.Orphan();
_rulesPopup = null;
}
public GuideEntryPrototype GetCoreRuleEntry()
{
var guide = _cfg.GetCVar(CCVars.RulesFile);
var guideEntryPrototype = _prototype.Index<GuideEntryPrototype>(guide);
return guideEntryPrototype;
}
public void OpenWindow()
{
if (_infoWindow == null || _infoWindow.Disposed)
{
_infoWindow = UIManager.CreateWindow<RulesAndInfoWindow>();
}
_infoWindow?.OpenCentered();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Postgres
{
/// <inheritdoc />
public partial class RemoveLastReadRules : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "last_read_rules",
table: "player");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "last_read_rules",
table: "player",
type: "timestamp with time zone",
nullable: true);
}
}
}

View File

@@ -648,10 +648,6 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("timestamp with time zone")
.HasColumnName("first_seen_time");
b.Property<DateTime?>("LastReadRules")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_read_rules");
b.Property<IPAddress>("LastSeenAddress")
.IsRequired()
.HasColumnType("inet")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Sqlite
{
/// <inheritdoc />
public partial class RemoveLastReadRules : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "last_read_rules",
table: "player");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "last_read_rules",
table: "player",
type: "TEXT",
nullable: true);
}
}
}

View File

@@ -608,10 +608,6 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("TEXT")
.HasColumnName("first_seen_time");
b.Property<DateTime?>("LastReadRules")
.HasColumnType("TEXT")
.HasColumnName("last_read_rules");
b.Property<string>("LastSeenAddress")
.IsRequired()
.HasColumnType("TEXT")

View File

@@ -520,8 +520,6 @@ namespace Content.Server.Database
public List<Round> Rounds { get; set; } = null!;
public List<AdminLogPlayer> AdminLogs { get; set; } = null!;
public DateTime? LastReadRules { get; set; }
public List<AdminNote> AdminNotesReceived { get; set; } = null!;
public List<AdminNote> AdminNotesCreated { get; set; } = null!;
public List<AdminNote> AdminNotesLastEdited { get; set; } = null!;

View File

@@ -7,6 +7,7 @@ using Content.Server.Database;
using Content.Server.Players;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.Info;
using Content.Shared.Players;
using Robust.Server.Console;
using Robust.Server.Player;
@@ -239,6 +240,7 @@ namespace Content.Server.Administration.Managers
_sawmill = _logManager.GetSawmill("admin");
_netMgr.RegisterNetMessage<MsgUpdateAdminStatus>();
_netMgr.RegisterNetMessage<ShowRulesPopupMessage>();
// Cache permissions for loaded console commands with the requisite attributes.
foreach (var (cmdName, cmd) in _consoleHost.AvailableCommands)

View File

@@ -1032,30 +1032,6 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
await db.DbContext.SaveChangesAsync();
}
public async Task<DateTimeOffset?> GetLastReadRules(NetUserId player)
{
await using var db = await GetDb();
return NormalizeDatabaseTime(await db.DbContext.Player
.Where(dbPlayer => dbPlayer.UserId == player)
.Select(dbPlayer => dbPlayer.LastReadRules)
.SingleOrDefaultAsync());
}
public async Task SetLastReadRules(NetUserId player, DateTimeOffset date)
{
await using var db = await GetDb();
var dbPlayer = await db.DbContext.Player.Where(dbPlayer => dbPlayer.UserId == player).SingleOrDefaultAsync();
if (dbPlayer == null)
{
return;
}
dbPlayer.LastReadRules = date.UtcDateTime;
await db.DbContext.SaveChangesAsync();
}
#endregion
#region Uploaded Resources Logs

View File

@@ -252,13 +252,6 @@ namespace Content.Server.Database
#endregion
#region Rules
Task<DateTimeOffset?> GetLastReadRules(NetUserId player);
Task SetLastReadRules(NetUserId player, DateTimeOffset time);
#endregion
#region Admin Notes
Task<int> AddAdminNote(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, NoteSeverity severity, bool secret, Guid createdBy, DateTimeOffset createdAt, DateTimeOffset? expiryTime);
@@ -707,18 +700,6 @@ namespace Content.Server.Database
return RunDbCommand(() => _db.PurgeUploadedResourceLogAsync(days));
}
public Task<DateTimeOffset?> GetLastReadRules(NetUserId player)
{
DbReadOpsMetric.Inc();
return RunDbCommand(() => _db.GetLastReadRules(player));
}
public Task SetLastReadRules(NetUserId player, DateTimeOffset time)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.SetLastReadRules(player, time));
}
public Task<int> AddAdminNote(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, NoteSeverity severity, bool secret, Guid createdBy, DateTimeOffset createdAt, DateTimeOffset? expiryTime)
{
DbWriteOpsMetric.Inc();

View File

@@ -10,7 +10,6 @@ using Content.Server.EUI;
using Content.Server.GameTicking;
using Content.Server.GhostKick;
using Content.Server.GuideGenerator;
using Content.Server.Info;
using Content.Server.IoC;
using Content.Server.Maps;
using Content.Server.NodeContainer.NodeGroups;
@@ -137,7 +136,6 @@ namespace Content.Server.Entry
IoCManager.Resolve<RecipeManager>().Initialize();
IoCManager.Resolve<IAdminManager>().Initialize();
IoCManager.Resolve<IAfkManager>().Initialize();
IoCManager.Resolve<RulesManager>().Initialize();
_euiManager.Initialize();
IoCManager.Resolve<IGameMapManager>().Initialize();

View File

@@ -1,35 +0,0 @@
using Content.Shared.CCVar;
using Content.Shared.Info;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
namespace Content.Server.Info;
public sealed class InfoSystem : EntitySystem
{
[Dependency] private readonly IResourceManager _res = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<RequestRulesMessage>(OnRequestRules);
}
private void OnRequestRules(RequestRulesMessage message, EntitySessionEventArgs eventArgs)
{
Log.Debug("Client requested rules.");
var title = Loc.GetString(_cfg.GetCVar(CCVars.RulesHeader));
var path = _cfg.GetCVar(CCVars.RulesFile);
var rules = "Server could not read its rules.";
try
{
rules = _res.ContentFileReadAllText($"/ServerInfo/{path}");
}
catch (Exception)
{
Log.Debug("Could not read server rules file.");
}
var response = new RulesMessage(title, rules);
RaiseNetworkEvent(response, eventArgs.SenderSession.Channel);
}
}

View File

@@ -1,48 +0,0 @@
using System.Net;
using Content.Server.Database;
using Content.Shared.CCVar;
using Content.Shared.Info;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
namespace Content.Server.Info;
public sealed class RulesManager : SharedRulesManager
{
[Dependency] private readonly IServerDbManager _dbManager = default!;
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private static DateTime LastValidReadTime => DateTime.UtcNow - TimeSpan.FromDays(60);
public void Initialize()
{
_netManager.RegisterNetMessage<ShouldShowRulesPopupMessage>();
_netManager.RegisterNetMessage<ShowRulesPopupMessage>();
_netManager.RegisterNetMessage<RulesAcceptedMessage>(OnRulesAccepted);
_netManager.Connected += OnConnected;
}
private async void OnConnected(object? sender, NetChannelArgs e)
{
if (IPAddress.IsLoopback(e.Channel.RemoteEndPoint.Address) && _cfg.GetCVar(CCVars.RulesExemptLocal))
{
return;
}
var lastRead = await _dbManager.GetLastReadRules(e.Channel.UserId);
if (lastRead > LastValidReadTime)
{
return;
}
var message = new ShouldShowRulesPopupMessage();
_netManager.ServerSendMessage(message, e.Channel);
}
private async void OnRulesAccepted(RulesAcceptedMessage message)
{
var date = DateTime.UtcNow;
await _dbManager.SetLastReadRules(message.MsgChannel.UserId, date);
}
}

View File

@@ -47,20 +47,16 @@ public sealed class ShowRulesCommand : IConsoleCommand
}
}
var locator = IoCManager.Resolve<IPlayerLocator>();
var located = await locator.LookupIdByNameOrIdAsync(target);
if (located == null)
var message = new ShowRulesPopupMessage { PopupTime = seconds };
if (!IoCManager.Resolve<IPlayerManager>().TryGetSessionByUsername(target, out var player))
{
shell.WriteError("Unable to find a player with that name.");
return;
return;
}
var netManager = IoCManager.Resolve<INetManager>();
var message = new SharedRulesManager.ShowRulesPopupMessage();
message.PopupTime = seconds;
var player = IoCManager.Resolve<IPlayerManager>().GetSessionById(located.UserId);
netManager.ServerSendMessage(message, player.Channel);
}
}

View File

@@ -9,7 +9,6 @@ using Content.Server.Database;
using Content.Server.Discord;
using Content.Server.EUI;
using Content.Server.GhostKick;
using Content.Server.Info;
using Content.Server.Maps;
using Content.Server.MoMMI;
using Content.Server.NodeContainer.NodeGroups;
@@ -47,7 +46,6 @@ namespace Content.Server.IoC
IoCManager.Register<IPlayerLocator, PlayerLocator>();
IoCManager.Register<IAfkManager, AfkManager>();
IoCManager.Register<IGameMapManager, GameMapManager>();
IoCManager.Register<RulesManager, RulesManager>();
IoCManager.Register<IBanManager, BanManager>();
IoCManager.Register<ContentNetworkResourceManager>();
IoCManager.Register<IAdminNotesManager, AdminNotesManager>();

View File

@@ -20,16 +20,10 @@ namespace Content.Shared.CCVar
CVarDef.Create("server.id", "unknown_server_id", CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Name of the rules txt file in the "Resources/Server Info" dir. Include the extension.
/// Guide Entry Prototype ID to be displayed as the server rules.
/// </summary>
public static readonly CVarDef<string> RulesFile =
CVarDef.Create("server.rules_file", "Rules.txt", CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// A loc string for what should be displayed as the title on the Rules window.
/// </summary>
public static readonly CVarDef<string> RulesHeader =
CVarDef.Create("server.rules_header", "ui-rules-header", CVar.REPLICATED | CVar.SERVER);
CVarDef.Create("server.rules_file", "DefaultRuleset", CVar.REPLICATED | CVar.SERVER);
/*
* Ambience
@@ -1795,7 +1789,13 @@ namespace Content.Shared.CCVar
/// Don't show rules to localhost/loopback interface.
/// </summary>
public static readonly CVarDef<bool> RulesExemptLocal =
CVarDef.Create("rules.exempt_local", true, CVar.SERVERONLY);
CVarDef.Create("rules.exempt_local", true, CVar.CLIENT);
/// <summary>
/// The next time the rules will popup for this client, expressed in minutes
/// </summary>
public static readonly CVarDef<string> RulesNextPopupTime =
CVarDef.Create("rules.next_popup_time", "Jan 1, 1997", CVar.CLIENTONLY | CVar.ARCHIVE);
/*

View File

@@ -0,0 +1,25 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared.Info;
/// <summary>
/// Sent by the server to show the rules to the client instantly.
/// </summary>
public sealed class ShowRulesPopupMessage : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Command;
public float PopupTime { get; set; }
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
PopupTime = buffer.ReadFloat();
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(PopupTime);
}
}

View File

@@ -1,28 +0,0 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Info
{
/// <summary>
/// A client request for server rules.
/// </summary>
[Serializable, NetSerializable]
public sealed class RequestRulesMessage : EntityEventArgs
{
}
/// <summary>
/// A server response with server rules.
/// </summary>
[Serializable, NetSerializable]
public sealed class RulesMessage : EntityEventArgs
{
public string Title;
public string Text;
public RulesMessage(string title, string rules)
{
Title = title;
Text = rules;
}
}
}

View File

@@ -1,60 +0,0 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared.Info;
public abstract class SharedRulesManager
{
/// <summary>
/// Sent by the server to show the rules to the client instantly.
/// </summary>
public sealed class ShowRulesPopupMessage : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Command;
public float PopupTime { get; set; }
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
PopupTime = buffer.ReadFloat();
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(PopupTime);
}
}
/// <summary>
/// Sent by the server when the client needs to display the rules on join.
/// </summary>
public sealed class ShouldShowRulesPopupMessage : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Command;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
}
}
/// <summary>
/// Sent by the client when it has accepted the rules.
/// </summary>
public sealed class RulesAcceptedMessage : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Command;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
}
}
}

View File

@@ -6,8 +6,7 @@ hostname = "[EN] Wizard's Den Salamander [US West RP]"
soft_max_players = 130
[server]
rules_file = "RP_Rules.txt"
rules_header = "ui-rules-header-rp"
rules_file = "MRPRuleset"
[whitelist]
enabled = true

View File

@@ -21,6 +21,9 @@ website = "https://spacestation14.io"
wiki = "https://wiki.spacestation14.io"
appeal = "https://appeal.ss14.io"
[server]
rules_file = "StandardRuleset"
[net]
max_connections = 1024

View File

@@ -4,3 +4,6 @@ ui-rules-header = Wizard's Den Official Server Rules
ui-rules-header-rp = Wizard's Den Roleplay Official Server Rules
ui-rules-accept = I have read and agree to follow the rules
ui-rules-wait = The accept button will be enabled after {$time} seconds.
ui-rules-button-home = Home
ui-rules-button-back = Back