diff --git a/Content.Client/Changelog/ChangelogManager.cs b/Content.Client/Changelog/ChangelogManager.cs index 48854ba45b..ef678af489 100644 --- a/Content.Client/Changelog/ChangelogManager.cs +++ b/Content.Client/Changelog/ChangelogManager.cs @@ -4,6 +4,8 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.IoC; using Robust.Shared.Serialization; @@ -18,11 +20,9 @@ namespace Content.Client.Changelog { public sealed class ChangelogManager { - // If you fork SS14, change this to have the changelog "last seen" date stored separately. - public const string ForkId = "Wizards"; - [Dependency] private readonly IResourceManager _resource = default!; [Dependency] private readonly ISerializationManager _serialization = default!; + [Dependency] private readonly IConfigurationManager _configManager = default!; public bool NewChangelogEntries { get; private set; } public int LastReadId { get; private set; } @@ -43,7 +43,7 @@ namespace Content.Client.Changelog NewChangelogEntries = false; NewChangelogEntriesChanged?.Invoke(); - using var file = _resource.UserData.Create(new ResourcePath($"/changelog_last_seen_{ForkId}")); + using var file = _resource.UserData.Create(new ResourcePath($"/changelog_last_seen_{_configManager.GetCVar(CCVars.ServerId)}")); using var sw = new StreamWriter(file); sw.Write(MaxId.ToString()); @@ -61,7 +61,7 @@ namespace Content.Client.Changelog MaxId = changelog.Max(c => c.Id); - var path = new ResourcePath($"/changelog_last_seen_{ForkId}"); + var path = new ResourcePath($"/changelog_last_seen_{_configManager.GetCVar(CCVars.ServerId)}"); if (_resource.UserData.Exists(path)) { LastReadId = int.Parse(_resource.UserData.ReadAllText(path)); diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index 4db2dea02c..e3ae7844c5 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -7,6 +7,7 @@ using Content.Client.EscapeMenu; using Content.Client.Eui; using Content.Client.Flash; using Content.Client.HUD; +using Content.Client.Info; using Content.Client.Input; using Content.Client.IoC; using Content.Client.Launcher; @@ -113,6 +114,7 @@ namespace Content.Client.Entry IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); + IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.InjectDependencies(this); diff --git a/Content.Client/HUD/GameHud.cs b/Content.Client/HUD/GameHud.cs index 8823980b44..6da65b2f20 100644 --- a/Content.Client/HUD/GameHud.cs +++ b/Content.Client/HUD/GameHud.cs @@ -104,7 +104,7 @@ namespace Content.Client.HUD private TopButton _buttonActionsMenu = default!; private TopButton _buttonAdminMenu = default!; private TopButton _buttonSandboxMenu = default!; - private InfoWindow _infoWindow = default!; + private RulesAndInfoWindow _rulesAndInfoWindow = default!; private TargetingDoll _targetingDoll = default!; private BoxContainer _combatPanelContainer = default!; private BoxContainer _topNotificationContainer = default!; @@ -301,9 +301,11 @@ namespace Content.Client.HUD _buttonInfo.OnToggled += a => ButtonInfoOnOnToggled(); - _infoWindow = new InfoWindow(); + _rulesAndInfoWindow = new RulesAndInfoWindow(); - _infoWindow.OnClose += () => _buttonInfo.Pressed = false; + IoCManager.Resolve().OpenRulesAndInfoWindow += OpenRulesAndInfoWindow; + + _rulesAndInfoWindow.OnClose += () => _buttonInfo.Pressed = false; _inputManager.SetInputCommand(ContentKeyFunctions.OpenInfo, InputCmdHandler.FromDelegate(s => ButtonInfoOnOnToggled())); @@ -428,25 +430,31 @@ namespace Content.Client.HUD LC.SetGrowVertical(VoteContainer, LC.GrowDirection.End); } + private void OpenRulesAndInfoWindow() + { + _rulesAndInfoWindow.OpenCentered(); + _buttonInfo.Pressed = true; + } + private void ButtonInfoOnOnToggled() { _buttonInfo.StyleClasses.Remove(TopButton.StyleClassRedTopButton); - if (_infoWindow.IsOpen) + if (_rulesAndInfoWindow.IsOpen) { - if (!_infoWindow.IsAtFront()) + if (!_rulesAndInfoWindow.IsAtFront()) { - _infoWindow.MoveToFront(); + _rulesAndInfoWindow.MoveToFront(); _buttonInfo.Pressed = true; } else { - _infoWindow.Close(); + _rulesAndInfoWindow.Close(); _buttonInfo.Pressed = false; } } else { - _infoWindow.OpenCentered(); + _rulesAndInfoWindow.OpenCentered(); _buttonInfo.Pressed = true; } } diff --git a/Content.Client/Info/InfoWindow.cs b/Content.Client/Info/RulesAndInfoWindow.cs similarity index 94% rename from Content.Client/Info/InfoWindow.cs rename to Content.Client/Info/RulesAndInfoWindow.cs index 517e39e636..25f5a8f5d7 100644 --- a/Content.Client/Info/InfoWindow.cs +++ b/Content.Client/Info/RulesAndInfoWindow.cs @@ -15,13 +15,14 @@ using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Info { - public sealed class InfoWindow : SS14Window + public sealed class RulesAndInfoWindow : SS14Window { + [Dependency] private readonly RulesManager _rulesManager = default!; [Dependency] private readonly IResourceCache _resourceManager = default!; private OptionsMenu optionsMenu; - public InfoWindow() + public RulesAndInfoWindow() { IoCManager.InjectDependencies(this); @@ -163,6 +164,13 @@ namespace Content.Client.Info optionsMenu.OpenCentered(); } + protected override void Opened() + { + base.Opened(); + + _rulesManager.SaveLastReadTime(); + } + private static IEnumerable Lines(TextReader reader) { while (true) diff --git a/Content.Client/Info/RulesManager.cs b/Content.Client/Info/RulesManager.cs new file mode 100644 index 0000000000..0dc6a95b11 --- /dev/null +++ b/Content.Client/Info/RulesManager.cs @@ -0,0 +1,55 @@ +using System; +using System.Globalization; +using System.IO; +using Content.Client.HUD; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.ContentPack; +using Robust.Shared.IoC; +using Robust.Shared.Network; +using Robust.Shared.Utility; + +namespace Content.Client.Info; + +public sealed class RulesManager +{ + [Dependency] private readonly IClientNetManager _clientNetManager = default!; + [Dependency] private readonly IResourceManager _resource = default!; + [Dependency] private readonly IConfigurationManager _configManager = default!; + + public event Action? OpenRulesAndInfoWindow; + + private void OnConnectStateChanged(ClientConnectionState state) + { + if (state != ClientConnectionState.Connected) + return; + + var path = new ResourcePath($"/rules_last_seen_{_configManager.GetCVar(CCVars.ServerId)}"); + var showRules = true; + if (_resource.UserData.Exists(path) + && DateTime.TryParse(_resource.UserData.ReadAllText(path), null, DateTimeStyles.AssumeUniversal, + out var lastReadTime)) + showRules = lastReadTime < DateTime.UtcNow - TimeSpan.FromDays(60); + else + SaveLastReadTime(); + + if (showRules) + OpenRulesAndInfoWindow?.Invoke(); + } + + /// + /// Ran when the user opens ("read") the rules, stores the new ID to disk. + /// + public void SaveLastReadTime() + { + using var file = _resource.UserData.Create(new ResourcePath($"/rules_last_seen_{_configManager.GetCVar(CCVars.ServerId)}")); + using var sw = new StreamWriter(file); + + sw.Write(DateTime.UtcNow.ToUniversalTime()); + } + + public void Initialize() + { + _clientNetManager.ClientConnectStateChanged += OnConnectStateChanged; + } +} diff --git a/Content.Client/Info/ServerInfo.cs b/Content.Client/Info/ServerInfo.cs index 10c798638c..d670a43458 100644 --- a/Content.Client/Info/ServerInfo.cs +++ b/Content.Client/Info/ServerInfo.cs @@ -32,7 +32,7 @@ namespace Content.Client.Info var uriOpener = IoCManager.Resolve(); var rulesButton = new Button() { Text = Loc.GetString("server-info-rules-button") }; - rulesButton.OnPressed += args => new InfoWindow().Open(); + rulesButton.OnPressed += args => new RulesAndInfoWindow().Open(); var discordButton = new Button {Text = Loc.GetString("server-info-discord-button") }; discordButton.OnPressed += args => uriOpener.OpenUri(UILinks.Discord); diff --git a/Content.Client/IoC/ClientContentIoC.cs b/Content.Client/IoC/ClientContentIoC.cs index 37b8175d8a..821f964596 100644 --- a/Content.Client/IoC/ClientContentIoC.cs +++ b/Content.Client/IoC/ClientContentIoC.cs @@ -5,6 +5,7 @@ using Content.Client.Clickable; using Content.Client.EscapeMenu; using Content.Client.Eui; using Content.Client.HUD; +using Content.Client.Info; using Content.Client.Items.Managers; using Content.Client.Module; using Content.Client.Parallax.Managers; @@ -44,6 +45,7 @@ namespace Content.Client.IoC IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); IoCManager.Register(); } } diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs index d2b8060ddb..074e3e90b3 100644 --- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs +++ b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs @@ -67,7 +67,7 @@ namespace Content.Client.Preferences.UI UpdateUI(); - RulesButton.OnPressed += _ => new InfoWindow().Open(); + RulesButton.OnPressed += _ => new RulesAndInfoWindow().Open(); preferencesManager.OnServerDataLoaded += UpdateUI; } diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index a456db86aa..62067fc697 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -7,6 +7,16 @@ namespace Content.Shared.CCVar [CVarDefs] public sealed class CCVars : CVars { + /* + * Server + */ + + /// + /// Change this to have the changelog and rules "last seen" date stored separately. + /// + public static readonly CVarDef ServerId = + CVarDef.Create("server.id", "unknown_server_id"); + /* * Ambience */