Skip to content

Commit

Permalink
Server player count filters.
Browse files Browse the repository at this point in the history
Based on #91

I ended up doing this somewhat differently. The ServerFilter model (and the DB table) were intended to be a set, so storing the actual count values in them didn't make much sense. Instead I decided to store the actual count values as a regular CVar. This also meant the code for the basic filters handling didn't need massive revamps.
  • Loading branch information
PJB3005 committed Aug 9, 2023
1 parent ee7b82c commit 3ac8e5a
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 11 deletions.
13 changes: 13 additions & 0 deletions SS14.Launcher/Models/Data/CVars.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using JetBrains.Annotations;
using SS14.Launcher.Utility;

namespace SS14.Launcher.Models.Data;

Expand Down Expand Up @@ -81,6 +82,18 @@ public static readonly CVarDef<bool> HasDismissedEarlyAccessWarning
/// Whether to display override assets (trans rights).
/// </summary>
public static readonly CVarDef<bool> OverrideAssets = CVarDef.Create("OverrideAssets", true);

/// <summary>
/// Stores the minimum player count value used by the "minimum player count" filter.
/// </summary>
/// <seealso cref="ServerFilter.PlayerCountMin"/>
public static readonly CVarDef<int> FilterPlayerCountMinValue = CVarDef.Create("FilterPlayerCountMinValue", 0);

/// <summary>
/// Stores the maximum player count value used by the "maximum player count" filter.
/// </summary>
/// <seealso cref="ServerFilter.PlayerCountMax"/>
public static readonly CVarDef<int> FilterPlayerCountMaxValue = CVarDef.Create("FilterPlayerCountMaxValue", 0);
}

/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public int PlayerCount
set => SetProperty(ref _playerCount, value);
}

/// <summary>
/// 0 means there's no maximum.
/// </summary>
public int SoftMaxPlayerCount
{
get => _softMaxPlayerCount;
Expand Down
8 changes: 7 additions & 1 deletion SS14.Launcher/Utility/ServerFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ 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
{
Language = 1,
Region = 2,
RolePlay = 3,
EighteenPlus = 4
EighteenPlus = 4,
PlayerCount = 5,
}
40 changes: 35 additions & 5 deletions SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterViewModel.cs
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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<int> CVar { get; }

public int CounterValue
{
get => CVar.Value;
set
{
CVar.Value = value;
Parent.CounterUpdated();
}
}

public ServerFilterCounterViewModel(
string name,
string shortName,
ServerFilter filter,
ICVarEntry<int> cVar,
ServerListFiltersViewModel parent) : base(name, shortName, filter, parent)
{
CVar = cVar;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public sealed partial class ServerListFiltersViewModel : ObservableObject
public ObservableCollection<ServerFilterViewModel> FiltersRolePlay => _filtersRolePlay;
public ObservableCollection<ServerFilterViewModel> 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
Expand All @@ -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);
}

/// <summary>
Expand Down Expand Up @@ -139,6 +170,7 @@ public void UpdatePresentFilters(IEnumerable<ServerStatusData> 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)
Expand All @@ -157,6 +189,13 @@ public void SetFilter(ServerFilter filter, bool value)
}
}

public void CounterUpdated()
{
FiltersUpdated?.Invoke();

_dataManager.CommitConfig();
}

/// <summary>
/// Apply active filter preferences to a list, removing all servers that do not fit the criteria.
/// </summary>
Expand All @@ -169,14 +208,25 @@ public void ApplyFilters(List<ServerStatusData> 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)
Expand Down Expand Up @@ -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;
}

Expand Down
23 changes: 23 additions & 0 deletions SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Width="300"
x:Class="SS14.Launcher.Views.MainWindowTabs.ServerFilterCounterView">
<Design.DataContext>
<mainWindowTabs:ServerFilterCounterViewModel />
</Design.DataContext>

<Grid ColumnDefinitions="Auto,*">
<CheckBox Content="{Binding ShortName}" Classes="ServerFilter" IsChecked="{Binding Selected}">
<ToolTip.Tip>
<TextBlock Text="{Binding Name}" />
</ToolTip.Tip>
</CheckBox>
<NumericUpDown Grid.Column="1" MinWidth="50" HorizontalAlignment="Left"
Value="{Binding CounterValue}" IsEnabled="{Binding Selected}"
Maximum="999" Minimum="0" />
</Grid>
</UserControl>
11 changes: 11 additions & 0 deletions SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Avalonia.Controls;

namespace SS14.Launcher.Views.MainWindowTabs;

public sealed partial class ServerFilterCounterView : UserControl
{
public ServerFilterCounterView()
{
InitializeComponent();
}
}
15 changes: 12 additions & 3 deletions SS14.Launcher/Views/MainWindowTabs/ServerListFiltersView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<Design.DataContext>
Expand All @@ -15,7 +15,7 @@
<WrapPanel />
</ItemsPanelTemplate>
<DataTemplate x:Key="FilterTemplate" DataType="mainWindowTabs:ServerFilterViewModel">
<mainWindowTabs1:ServerFilterView DataContext="{Binding}" />
<mwtv:ServerFilterView DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>

Expand All @@ -40,7 +40,16 @@
ItemsPanel="{StaticResource PanelTemplate}" ItemTemplate="{StaticResource FilterTemplate}"/>
</DockPanel>
<DockPanel Classes="ServerFilterGroup">
<TextBlock MinWidth="150" DockPanel.Dock="Left" Classes="SubText" Text="18+" />
<TextBlock MinWidth="150" DockPanel.Dock="Left" Classes="SubText" Text="Player count" />
<WrapPanel>
<mwtv:ServerFilterCounterView DataContext="{Binding FilterPlayerCountMinimum}" />
<mwtv:ServerFilterCounterView DataContext="{Binding FilterPlayerCountMaximum}" />
<mwtv:ServerFilterView DataContext="{Binding FilterPlayerCountHideEmpty}" />
<mwtv:ServerFilterView DataContext="{Binding FilterPlayerCountHideFull}" />
</WrapPanel>
</DockPanel>
<DockPanel Classes="ServerFilterGroup">
<TextBlock MinWidth="150" DockPanel.Dock="Left" VerticalAlignment="Center" Classes="SubText" Text="18+" />
<ItemsControl Items="{Binding FiltersEighteenPlus}"
ItemsPanel="{StaticResource PanelTemplate}" ItemTemplate="{StaticResource FilterTemplate}"/>
</DockPanel>
Expand Down

0 comments on commit 3ac8e5a

Please sign in to comment.