Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues #19: Player Count Filters #91

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions SS14.Launcher/Utility/ServerFilter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace SS14.Launcher.Utility;
namespace SS14.Launcher.Utility;

/// <summary>
/// Specifies a single filter checkbox the user can toggle to filter servers.
Expand Down Expand Up @@ -49,5 +49,10 @@ public enum ServerFilterCategory : byte
Language = 1,
Region = 2,
RolePlay = 3,
EighteenPlus = 4
EighteenPlus = 4,
IsServerFull = 5,
PlayerMin = 6,
PlayerMax = 7,
MinEnabled = 8,
MaxEnabled = 9
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using SS14.Launcher.Utility;

namespace SS14.Launcher.ViewModels.MainWindowTabs;

public class ServerFilterBaseViewModel : ObservableObject
{
public ServerFilter Filter { get; protected set; }
protected readonly ServerListFiltersViewModel _parent;

public string Name { get; }
public string ShortName { get; }

public ServerFilterBaseViewModel(
string name,
string shortName,
ServerFilter filter,
ServerListFiltersViewModel parent)
{
Filter = filter;
_parent = parent;
Name = name;
ShortName = shortName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using SS14.Launcher.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SS14.Launcher.ViewModels.MainWindowTabs
{
public sealed class ServerFilterIntegerViewModel: ServerFilterBaseViewModel
{
public int? Data
{
get
{
bool isVal = int.TryParse(Filter.Data, out var val);
return isVal ? val : null;
}

set
{
var filter_val = value is not null ? value.ToString() : string.Empty;
ServerFilter filter = new ServerFilter(Filter.Category, filter_val);

Check warning on line 24 in SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterIntegerViewModel.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'Data' in 'ServerFilter.ServerFilter(ServerFilterCategory Category, string Data)'.

Check warning on line 24 in SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterIntegerViewModel.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'Data' in 'ServerFilter.ServerFilter(ServerFilterCategory Category, string Data)'.
_parent.ReplaceFilter(filter, Filter);
Filter = filter;
}
}

public int? Maximum { get; }
public int? Minimum { get; }
public int Increment { get; }


public ServerFilterIntegerViewModel(
string name,
string shortName,
ServerFilter filter,
int increment,
ServerListFiltersViewModel parent,
int? max = null,
int? min = null) : base(name, shortName, filter, parent)
{
Maximum = max;
Minimum = min;
Increment = increment;
}
}
}
17 changes: 4 additions & 13 deletions SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using SS14.Launcher.Utility;

namespace SS14.Launcher.ViewModels.MainWindowTabs;

public sealed class ServerFilterViewModel : ObservableObject
public sealed class ServerFilterViewModel : ServerFilterBaseViewModel
{
public ServerFilter Filter { get; }
private readonly ServerListFiltersViewModel _parent;

public string Name { get; }
public string ShortName { get; }

public bool Selected
{
get => _parent.GetFilter(Filter);
get => _parent.FilterExists(Filter);
set => _parent.SetFilter(Filter, value);
}

public ServerFilterViewModel(
string name,
string shortName,
ServerFilter filter,
ServerListFiltersViewModel parent)
ServerListFiltersViewModel parent) : base(name, shortName, filter, parent)
{
Filter = filter;
_parent = parent;
Name = name;
ShortName = shortName;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
Expand All @@ -14,6 +14,9 @@ namespace SS14.Launcher.ViewModels.MainWindowTabs;

public sealed partial class ServerListFiltersViewModel : ObservableObject
{
private const int NO_PLAYER_MAX_NUM = 0;
private const int NO_PLAYER_MIN_NUM = 0;

private readonly DataManager _dataManager;

private int _totalServers;
Expand All @@ -23,11 +26,13 @@ public sealed partial class ServerListFiltersViewModel : ObservableObject
private readonly FilterListCollection _filtersRegion = new();
private readonly FilterListCollection _filtersRolePlay = new();
private readonly FilterListCollection _filtersEighteenPlus = new();
private readonly FilterListCollection _filtersPlayerCount = new();

public ObservableCollection<ServerFilterViewModel> FiltersLanguage => _filtersLanguage;
public ObservableCollection<ServerFilterViewModel> FiltersRegion => _filtersRegion;
public ObservableCollection<ServerFilterViewModel> FiltersRolePlay => _filtersRolePlay;
public ObservableCollection<ServerFilterViewModel> FiltersEighteenPlus => _filtersEighteenPlus;
public ObservableCollection<ServerFilterBaseViewModel> FiltersLanguage => _filtersLanguage;
public ObservableCollection<ServerFilterBaseViewModel> FiltersRegion => _filtersRegion;
public ObservableCollection<ServerFilterBaseViewModel> FiltersRolePlay => _filtersRolePlay;
public ObservableCollection<ServerFilterBaseViewModel> FiltersEighteenPlus => _filtersEighteenPlus;
public ObservableCollection<ServerFilterBaseViewModel> FiltersPlayerCount => _filtersPlayerCount;

public event Action? FiltersUpdated;

Expand All @@ -45,12 +50,26 @@ public int FilteredServers

public ServerListFiltersViewModel(DataManager dataManager)
{
const int PLAYER_COUNT_INCREMENT = 1;
_dataManager = dataManager;

FiltersEighteenPlus.Add(new ServerFilterViewModel("Yes", "Yes",
new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataTrue), this));
FiltersEighteenPlus.Add(new ServerFilterViewModel("No", "No",
new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataFalse), this));

ServerFilter maxFilter = FilterCategoryExists(ServerFilterCategory.PlayerMax) ? GetFilterByCategory(ServerFilterCategory.PlayerMax) : new ServerFilter(ServerFilterCategory.PlayerMax, NO_PLAYER_MAX_NUM.ToString());
ServerFilter minFilter = FilterCategoryExists(ServerFilterCategory.PlayerMin) ? GetFilterByCategory(ServerFilterCategory.PlayerMin) : new ServerFilter(ServerFilterCategory.PlayerMin, NO_PLAYER_MIN_NUM.ToString());
FiltersPlayerCount.Add(new ServerFilterViewModel("Filter Full Servers", "Filter Full",
new ServerFilter(ServerFilterCategory.IsServerFull, ServerFilter.DataTrue), this));
FiltersPlayerCount.Add(new ServerFilterViewModel("Enable Min Filter", "Filter Min",
new ServerFilter(ServerFilterCategory.MinEnabled, ServerFilter.DataTrue), this));
FiltersPlayerCount.Add(new ServerFilterIntegerViewModel("Min Player Count", "Filter Min",
minFilter, PLAYER_COUNT_INCREMENT, this, min: NO_PLAYER_MIN_NUM));
FiltersPlayerCount.Add(new ServerFilterViewModel("Enable Max Filter", "Filter Max",
new ServerFilter(ServerFilterCategory.MaxEnabled, ServerFilter.DataTrue), this));
FiltersPlayerCount.Add(new ServerFilterIntegerViewModel($"Max Player Count", "Filter Max",
maxFilter, PLAYER_COUNT_INCREMENT, this, min: NO_PLAYER_MAX_NUM));
}

/// <summary>
Expand Down Expand Up @@ -139,7 +158,10 @@ public void UpdatePresentFilters(IEnumerable<ServerStatusData> servers)
_filtersRolePlay.SetItems(filtersRolePlay);
}

public bool GetFilter(ServerFilter filter) => _dataManager.Filters.Contains(filter);
public bool FilterExists(ServerFilter filter) => _dataManager.Filters.Contains(filter);
public bool FilterCategoryExists(ServerFilterCategory category) => _dataManager.Filters.Where((filter) => filter.Category == category).Count() > 0;

public ServerFilter GetFilterByCategory(ServerFilterCategory category) => _dataManager.Filters.Where((filter) => filter.Category == category).FirstOrDefault();

public void SetFilter(ServerFilter filter, bool value)
{
Expand All @@ -157,6 +179,15 @@ public void SetFilter(ServerFilter filter, bool value)
}
}

public void ReplaceFilter(ServerFilter new_filter, ServerFilter old_filter)
{
if (_dataManager.Filters.Contains(old_filter))
_dataManager.Filters.Remove(old_filter);
_dataManager.Filters.Add(new_filter);
_dataManager.CommitConfig();
FiltersUpdated?.Invoke();
}

/// <summary>
/// Apply active filter preferences to a list, removing all servers that do not fit the criteria.
/// </summary>
Expand All @@ -168,15 +199,22 @@ public void ApplyFilters(List<ServerStatusData> list)
var categorySetLanguage = GetCategoryFilterSet(FiltersLanguage);
var categorySetRegion = GetCategoryFilterSet(FiltersRegion);
var categorySetRolePlay = GetCategoryFilterSet(FiltersRolePlay);
bool isFull = FilterExists(new ServerFilter(ServerFilterCategory.IsServerFull, ServerFilter.DataTrue));
bool isMaxEnabled = FilterExists(new ServerFilter(ServerFilterCategory.MaxEnabled, ServerFilter.DataTrue));
bool isMinEnabled = FilterExists(new ServerFilter(ServerFilterCategory.MinEnabled, ServerFilter.DataTrue));

// Precache PlayerMax & PlayerMin
bool isValidMax = int.TryParse(GetFilterByCategory(ServerFilterCategory.PlayerMax).Data, out int playerMax) && isMaxEnabled;
bool isValidMin = int.TryParse(GetFilterByCategory(ServerFilterCategory.PlayerMin).Data, out int playerMin) && isMinEnabled;

// Precache 18+ bool.
bool? eighteenPlus = null;
if (GetFilter(new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataTrue)))
if (FilterExists(new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataTrue)))
{
eighteenPlus = true;
}

if (GetFilter(new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataFalse)))
if (FilterExists(new ServerFilter(ServerFilterCategory.EighteenPlus, ServerFilter.DataFalse)))
{
// Having both
if (eighteenPlus == true)
Expand All @@ -199,6 +237,14 @@ public void ApplyFilters(List<ServerStatusData> list)

bool DoesServerMatch(ServerStatusData server)
{
// Max Player Count Being 0 means an infinite amount of slots
if (isFull && server.SoftMaxPlayerCount > 0 && server.PlayerCount >= server.SoftMaxPlayerCount)
return false;
if (isValidMax && server.PlayerCount > playerMax)
return false;
if (isValidMin && server.PlayerCount < playerMin)
return false;

// 18+ checks
if (eighteenPlus != null)
{
Expand All @@ -219,7 +265,7 @@ bool DoesServerMatch(ServerStatusData server)
return true;
}

HashSet<string>? GetCategoryFilterSet(IEnumerable<ServerFilterViewModel> visible)
HashSet<string>? GetCategoryFilterSet(IEnumerable<ServerFilterBaseViewModel> visible)
{
// Filters are persisted, so it's possible to get a filter that isn't visible
// (because no servers have the tag right now),
Expand Down Expand Up @@ -298,9 +344,9 @@ public override int Compare(ServerFilterViewModel x, ServerFilterViewModel y)
}
}

private sealed class FilterListCollection : ObservableCollection<ServerFilterViewModel>
private sealed class FilterListCollection : ObservableCollection<ServerFilterBaseViewModel>
{
public void SetItems(IEnumerable<ServerFilterViewModel> items)
public void SetItems(IEnumerable<ServerFilterBaseViewModel> items)
{
Items.Clear();

Expand Down
20 changes: 20 additions & 0 deletions SS14.Launcher/Views/MainWindowTabs/ServerFilterIntegerView.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<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"
x:Class="SS14.Launcher.Views.MainWindowTabs.ServerFilterIntegerView">
<Design.DataContext>
<mainWindowTabs:ServerFilterIntegerViewModel/>
</Design.DataContext>

<WrapPanel>
<NumericUpDown Classes="ServerFilter" Value="{Binding Data}" Minimum="{Binding Minimum}" Maximum="{Binding Maximum}" Increment="{Binding Increment}">
<ToolTip.Tip>
<TextBlock Text="{Binding Name}" />
</ToolTip.Tip>
</NumericUpDown>
<TextBlock Text="{Binding ShortName}" VerticalAlignment="Center" Margin="5,0,25,0"/>
</WrapPanel>
</UserControl>
11 changes: 11 additions & 0 deletions SS14.Launcher/Views/MainWindowTabs/ServerFilterIntegerView.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 ServerFilterIntegerView : UserControl
{
public ServerFilterIntegerView()
{
InitializeComponent();
}
}
26 changes: 19 additions & 7 deletions SS14.Launcher/Views/MainWindowTabs/ServerListFiltersView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,19 @@

<UserControl.Resources>
<ItemsPanelTemplate x:Key="PanelTemplate">
<WrapPanel />
<WrapPanel>
</WrapPanel>
</ItemsPanelTemplate>
<DataTemplate x:Key="FilterTemplate" DataType="mainWindowTabs:ServerFilterViewModel">
</UserControl.Resources>

<UserControl.DataTemplates>
<DataTemplate DataType="mainWindowTabs:ServerFilterViewModel">
<mainWindowTabs1:ServerFilterView DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>
<DataTemplate DataType="mainWindowTabs:ServerFilterIntegerViewModel">
<mainWindowTabs1:ServerFilterIntegerView DataContext="{Binding}" />
</DataTemplate>
</UserControl.DataTemplates>

<DockPanel>
<TextBlock DockPanel.Dock="Top" Text="Filters" Classes="SubText" Margin="4 4 4 8" />
Expand All @@ -27,22 +34,27 @@
<DockPanel Classes="ServerFilterGroup">
<TextBlock MinWidth="150" DockPanel.Dock="Left" Classes="SubText" Text="Language" />
<ItemsControl Items="{Binding FiltersLanguage}"
ItemsPanel="{StaticResource PanelTemplate}" ItemTemplate="{StaticResource FilterTemplate}"/>
ItemsPanel="{StaticResource PanelTemplate}"/>
</DockPanel>
<DockPanel Classes="ServerFilterGroup">
<TextBlock MinWidth="150" DockPanel.Dock="Left" Classes="SubText" Text="Region" />
<ItemsControl Items="{Binding FiltersRegion}"
ItemsPanel="{StaticResource PanelTemplate}" ItemTemplate="{StaticResource FilterTemplate}"/>
ItemsPanel="{StaticResource PanelTemplate}"/>
</DockPanel>
<DockPanel Classes="ServerFilterGroup">
<TextBlock MinWidth="150" DockPanel.Dock="Left" Classes="SubText" Text="Role-play level" />
<ItemsControl Items="{Binding FiltersRolePlay}"
ItemsPanel="{StaticResource PanelTemplate}" ItemTemplate="{StaticResource FilterTemplate}"/>
ItemsPanel="{StaticResource PanelTemplate}"/>
</DockPanel>
<DockPanel Classes="ServerFilterGroup">
<TextBlock MinWidth="150" DockPanel.Dock="Left" Classes="SubText" Text="18+" />
<ItemsControl Items="{Binding FiltersEighteenPlus}"
ItemsPanel="{StaticResource PanelTemplate}" ItemTemplate="{StaticResource FilterTemplate}"/>
ItemsPanel="{StaticResource PanelTemplate}"/>
</DockPanel>
<DockPanel Classes="ServerFilterGroup">
<TextBlock MinWidth="150" DockPanel.Dock="Left" Classes="SubText" Text="Filter Player Count" />
<ItemsControl Items="{Binding FiltersPlayerCount}"
ItemsPanel="{StaticResource PanelTemplate}"/>
</DockPanel>
</StackPanel>
</ScrollViewer>
Expand Down
Loading