diff --git a/SS14.Launcher/Models/Data/CVars.cs b/SS14.Launcher/Models/Data/CVars.cs index ce71d80f..dc5b4d6b 100644 --- a/SS14.Launcher/Models/Data/CVars.cs +++ b/SS14.Launcher/Models/Data/CVars.cs @@ -1,5 +1,6 @@ using System; using JetBrains.Annotations; +using SS14.Launcher.Utility; namespace SS14.Launcher.Models.Data; @@ -81,6 +82,18 @@ public static readonly CVarDef HasDismissedEarlyAccessWarning /// Whether to display override assets (trans rights). /// public static readonly CVarDef OverrideAssets = CVarDef.Create("OverrideAssets", true); + + /// + /// Stores the minimum player count value used by the "minimum player count" filter. + /// + /// + public static readonly CVarDef FilterPlayerCountMinValue = CVarDef.Create("FilterPlayerCountMinValue", 0); + + /// + /// Stores the maximum player count value used by the "maximum player count" filter. + /// + /// + public static readonly CVarDef FilterPlayerCountMaxValue = CVarDef.Create("FilterPlayerCountMaxValue", 0); } /// diff --git a/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs b/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs index 18da1e81..66296729 100644 --- a/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs +++ b/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs @@ -61,6 +61,9 @@ public int PlayerCount set => SetProperty(ref _playerCount, value); } + /// + /// 0 means there's no maximum. + /// public int SoftMaxPlayerCount { get => _softMaxPlayerCount; diff --git a/SS14.Launcher/Utility/ServerFilter.cs b/SS14.Launcher/Utility/ServerFilter.cs index 35c3a52c..a56c8d66 100644 --- a/SS14.Launcher/Utility/ServerFilter.cs +++ b/SS14.Launcher/Utility/ServerFilter.cs @@ -42,6 +42,11 @@ public record struct ServerFilter(ServerFilterCategory Category, string Data) public const string DataTrue = "true"; public const string DataFalse = "false"; + + public static readonly ServerFilter PlayerCountHideFull = new(ServerFilterCategory.PlayerCount, "hide_full"); + public static readonly ServerFilter PlayerCountHideEmpty = new(ServerFilterCategory.PlayerCount, "hide_empty"); + public static readonly ServerFilter PlayerCountMax = new(ServerFilterCategory.PlayerCount, "max"); + public static readonly ServerFilter PlayerCountMin = new(ServerFilterCategory.PlayerCount, "min"); } public enum ServerFilterCategory : byte @@ -49,5 +54,6 @@ public enum ServerFilterCategory : byte Language = 1, Region = 2, RolePlay = 3, - EighteenPlus = 4 + EighteenPlus = 4, + PlayerCount = 5, } diff --git a/SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterViewModel.cs b/SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterViewModel.cs index fa433341..a78d3b3e 100644 --- a/SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterViewModel.cs +++ b/SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterViewModel.cs @@ -1,20 +1,25 @@ using Microsoft.Toolkit.Mvvm.ComponentModel; +using SS14.Launcher.Models.Data; using SS14.Launcher.Utility; namespace SS14.Launcher.ViewModels.MainWindowTabs; -public sealed class ServerFilterViewModel : ObservableObject +public class ServerFilterViewModel : ObservableObject { public ServerFilter Filter { get; } - private readonly ServerListFiltersViewModel _parent; + protected readonly ServerListFiltersViewModel Parent; public string Name { get; } public string ShortName { get; } public bool Selected { - get => _parent.GetFilter(Filter); - set => _parent.SetFilter(Filter, value); + get => Parent.GetFilter(Filter); + set + { + Parent.SetFilter(Filter, value); + OnPropertyChanged(); + } } public ServerFilterViewModel( @@ -24,8 +29,33 @@ public ServerFilterViewModel( ServerListFiltersViewModel parent) { Filter = filter; - _parent = parent; + Parent = parent; Name = name; ShortName = shortName; } } + +public sealed class ServerFilterCounterViewModel : ServerFilterViewModel +{ + public ICVarEntry CVar { get; } + + public int CounterValue + { + get => CVar.Value; + set + { + CVar.Value = value; + Parent.CounterUpdated(); + } + } + + public ServerFilterCounterViewModel( + string name, + string shortName, + ServerFilter filter, + ICVarEntry cVar, + ServerListFiltersViewModel parent) : base(name, shortName, filter, parent) + { + CVar = cVar; + } +} diff --git a/SS14.Launcher/ViewModels/MainWindowTabs/ServerListFiltersViewModel.cs b/SS14.Launcher/ViewModels/MainWindowTabs/ServerListFiltersViewModel.cs index 03f27a90..447aed07 100644 --- a/SS14.Launcher/ViewModels/MainWindowTabs/ServerListFiltersViewModel.cs +++ b/SS14.Launcher/ViewModels/MainWindowTabs/ServerListFiltersViewModel.cs @@ -29,6 +29,11 @@ public sealed partial class ServerListFiltersViewModel : ObservableObject public ObservableCollection FiltersRolePlay => _filtersRolePlay; public ObservableCollection FiltersEighteenPlus => _filtersEighteenPlus; + public ServerFilterViewModel FilterPlayerCountHideEmpty { get; } + public ServerFilterViewModel FilterPlayerCountHideFull { get; } + public ServerFilterCounterViewModel FilterPlayerCountMinimum { get; } + public ServerFilterCounterViewModel FilterPlayerCountMaximum { get; } + public event Action? FiltersUpdated; public int TotalServers @@ -51,6 +56,32 @@ public ServerListFiltersViewModel(DataManager dataManager) new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataTrue), this)); FiltersEighteenPlus.Add(new ServerFilterViewModel("No", "No", new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataFalse), this)); + + FilterPlayerCountHideEmpty = new ServerFilterViewModel( + "Servers with no players will not be shown", + "Hide empty", + ServerFilter.PlayerCountHideEmpty, + this); + + FilterPlayerCountHideFull = new ServerFilterViewModel( + "Servers that are full will not be shown", + "Hide full", + ServerFilter.PlayerCountHideFull, + this); + + FilterPlayerCountMinimum = new ServerFilterCounterViewModel( + "Servers with less players will not be shown", + "Minimum: ", + ServerFilter.PlayerCountMin, + _dataManager.GetCVarEntry(CVars.FilterPlayerCountMinValue), + this); + + FilterPlayerCountMaximum = new ServerFilterCounterViewModel( + "Servers with more players will not be shown", + "Maximum: ", + ServerFilter.PlayerCountMax, + _dataManager.GetCVarEntry(CVars.FilterPlayerCountMaxValue), + this); } /// @@ -139,6 +170,7 @@ public void UpdatePresentFilters(IEnumerable servers) _filtersRolePlay.SetItems(filtersRolePlay); } + public bool GetFilter(ServerFilterCategory category, string data) => GetFilter(new ServerFilter(category, data)); public bool GetFilter(ServerFilter filter) => _dataManager.Filters.Contains(filter); public void SetFilter(ServerFilter filter, bool value) @@ -157,6 +189,13 @@ public void SetFilter(ServerFilter filter, bool value) } } + public void CounterUpdated() + { + FiltersUpdated?.Invoke(); + + _dataManager.CommitConfig(); + } + /// /// Apply active filter preferences to a list, removing all servers that do not fit the criteria. /// @@ -169,14 +208,25 @@ public void ApplyFilters(List list) var categorySetRegion = GetCategoryFilterSet(FiltersRegion); var categorySetRolePlay = GetCategoryFilterSet(FiltersRolePlay); + var hideEmpty = GetFilter(ServerFilter.PlayerCountHideEmpty); + var hideFull = GetFilter(ServerFilter.PlayerCountHideFull); + + int? minPlayerCount = null; + int? maxPlayerCount = null; + if (GetFilter(ServerFilter.PlayerCountMin)) + minPlayerCount = _dataManager.GetCVar(CVars.FilterPlayerCountMinValue); + + if (GetFilter(ServerFilter.PlayerCountMax)) + maxPlayerCount = _dataManager.GetCVar(CVars.FilterPlayerCountMaxValue); + // Precache 18+ bool. bool? eighteenPlus = null; - if (GetFilter(new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataTrue))) + if (GetFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataTrue)) { eighteenPlus = true; } - if (GetFilter(new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataFalse))) + if (GetFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataFalse)) { // Having both if (eighteenPlus == true) @@ -216,6 +266,19 @@ bool DoesServerMatch(ServerStatusData server) if (!CheckCategoryFilterSet(categorySetRolePlay, server.Tags, Tags.TagRolePlay)) return false; + // Player count checks. + if (hideEmpty && server.PlayerCount == 0) + return false; + + if (hideFull && server.SoftMaxPlayerCount != 0 && server.PlayerCount >= server.SoftMaxPlayerCount) + return false; + + if (minPlayerCount != null && server.PlayerCount < minPlayerCount) + return false; + + if (maxPlayerCount != null && server.PlayerCount > maxPlayerCount) + return false; + return true; } diff --git a/SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml b/SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml new file mode 100644 index 00000000..7e0949d9 --- /dev/null +++ b/SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml.cs b/SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml.cs new file mode 100644 index 00000000..e077d4bf --- /dev/null +++ b/SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace SS14.Launcher.Views.MainWindowTabs; + +public sealed partial class ServerFilterCounterView : UserControl +{ + public ServerFilterCounterView() + { + InitializeComponent(); + } +} diff --git a/SS14.Launcher/Views/MainWindowTabs/ServerListFiltersView.xaml b/SS14.Launcher/Views/MainWindowTabs/ServerListFiltersView.xaml index 634275e9..2d10e11d 100644 --- a/SS14.Launcher/Views/MainWindowTabs/ServerListFiltersView.xaml +++ b/SS14.Launcher/Views/MainWindowTabs/ServerListFiltersView.xaml @@ -3,7 +3,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mainWindowTabs="clr-namespace:SS14.Launcher.ViewModels.MainWindowTabs" - xmlns:mainWindowTabs1="clr-namespace:SS14.Launcher.Views.MainWindowTabs" + xmlns:mwtv="clr-namespace:SS14.Launcher.Views.MainWindowTabs" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SS14.Launcher.Views.MainWindowTabs.ServerListFiltersView"> @@ -15,7 +15,7 @@ - + @@ -40,7 +40,16 @@ ItemsPanel="{StaticResource PanelTemplate}" ItemTemplate="{StaticResource FilterTemplate}"/> - + + + + + + + + + +