Table of Contents

Class ServerViewModel

Namespace
McServerLauncher.ViewModels
Assembly
McServerLauncher.dll

The crossplay half of ServerViewModel: Geyser, the Bedrock tunnel and the address.

public class ServerViewModel : ObservableObject, INotifyPropertyChanged, INotifyPropertyChanging
Inheritance
ServerViewModel
Implements
Inherited Members

Remarks

Split out because the file had reached two thousand lines carrying the process, the console, the players, the ports, the tunnels, crossplay, the backups, Java and the notifications. This is the part that has grown most and is likeliest to grow again, and it is a closed subject: everything here is about one question, and nothing outside it needs any of these members.

A move, not a rewrite. The class was already partial, so not one instruction changed — which is what makes it safe to do at all, and why the whole test suite must give the identical result.

Constructors

ServerViewModel(ServerConfig)

public ServerViewModel(ServerConfig config)

Parameters

config ServerConfig

Properties

AddToWhitelistCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.AddToWhitelist().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand AddToWhitelistCommand { get; }

Property Value

IAsyncRelayCommand

Backups

public ServerBackupsViewModel Backups { get; }

Property Value

ServerBackupsViewModel

BanPlayerCommand

Gets an IAsyncRelayCommand<T> instance wrapping BanPlayer(string).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<string?> BanPlayerCommand { get; }

Property Value

IAsyncRelayCommand<string>

BannedPlayers

Banned players (banned-players.json).

public ObservableCollection<string> BannedPlayers { get; }

Property Value

ObservableCollection<string>

BedrockHost

The Bedrock host and port, shown separately. Null when there is no Bedrock tunnel.

[ExcludeFromCodeCoverage]
public string? BedrockHost { get; set; }

Property Value

string

BedrockLocalPortText

The local UDP port Geyser listens on. Known from the moment crossplay is set up.

public string BedrockLocalPortText { get; }

Property Value

string

BedrockPortText

[ExcludeFromCodeCoverage]
public string? BedrockPortText { get; set; }

Property Value

string

BedrockPortsInUse

The Bedrock ports the other servers have already been given.

public Func<IEnumerable<int>>? BedrockPortsInUse { get; set; }

Property Value

Func<IEnumerable<int>>

Remarks

Supplied by MainViewModel, which is the only thing that knows the other servers exist. It matters because the free-port search asks the operating system which UDP ports are bound right now: set crossplay up on two stopped servers and both are handed 19132, and the collision only shows up later as the second Geyser failing to bind.

BedrockState

How far along the Bedrock address is. Drives the explanation under the panel.

[ExcludeFromCodeCoverage]
public BedrockAddressState BedrockState { get; set; }

Property Value

BedrockAddressState

BedrockStateText

One line saying what is happening, so the panel is never blank without a reason.

public string BedrockStateText { get; }

Property Value

string

CanStart

public bool CanStart { get; }

Property Value

bool

CanStop

public bool CanStop { get; }

Property Value

bool

ClearConsoleCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.ClearConsole().

[ExcludeFromCodeCoverage]
public IRelayCommand ClearConsoleCommand { get; }

Property Value

IRelayCommand

CommandHelp

Common commands with their explanation (for the console help).

public IReadOnlyList<CommandHelp> CommandHelp { get; }

Property Value

IReadOnlyList<CommandHelp>

CommandText

[ExcludeFromCodeCoverage]
public string CommandText { get; set; }

Property Value

string

Config

public ServerConfig Config { get; }

Property Value

ServerConfig

ConnectedPlayers

Players connected right now (live, read from the console).

public ObservableCollection<string> ConnectedPlayers { get; }

Property Value

ObservableCollection<string>

ConsoleFilter

[ExcludeFromCodeCoverage]
public string ConsoleFilter { get; set; }

Property Value

string

ConsoleKinds

One switch per kind of line, in the order they appear along the top of the console.

public IReadOnlyList<ConsoleKindFilter> ConsoleKinds { get; }

Property Value

IReadOnlyList<ConsoleKindFilter>

Remarks

Ordered by how much they matter rather than by the enum, so the two that make somebody open the console at all come first and are never the ones that wrap out of sight.

ConsoleLines

Lines of the embedded console (server stdout/stderr + the launcher's own).

public BulkObservableCollection<ConsoleLine> ConsoleLines { get; }

Property Value

BulkObservableCollection<ConsoleLine>

CopyBedrockAddressCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.CopyBedrockAddress().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand CopyBedrockAddressCommand { get; }

Property Value

IAsyncRelayCommand

CopyTunnelAddressCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.CopyTunnelAddress().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand CopyTunnelAddressCommand { get; }

Property Value

IAsyncRelayCommand

CpuSeries

[ExcludeFromCodeCoverage]
public IReadOnlyList<double>? CpuSeries { get; set; }

Property Value

IReadOnlyList<double>

CpuText

[ExcludeFromCodeCoverage]
public string CpuText { get; set; }

Property Value

string

DeopPlayerCommand

Gets an IAsyncRelayCommand<T> instance wrapping DeopPlayer(string).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<string?> DeopPlayerCommand { get; }

Property Value

IAsyncRelayCommand<string>

GameVersionText

Minecraft version (empty until known).

public string GameVersionText { get; }

Property Value

string

HasBedrockAddress

True once there is a public Bedrock address worth showing.

public bool HasBedrockAddress { get; }

Property Value

bool

HasIcon

public bool HasIcon { get; }

Property Value

bool

HasIdleCountdown

True while there is a countdown to show.

public bool HasIdleCountdown { get; }

Property Value

bool

IdleCountdownText

How long until the empty server stops itself, or null when nothing is counting.

[ExcludeFromCodeCoverage]
public string? IdleCountdownText { get; set; }

Property Value

string

Remarks

Only set while the clock is actually running, so the UI can bind its visibility straight to this: an idle countdown showing "0:00" on a server nobody configured to stop would be a lie.

IsCommandHelpOpen

[ExcludeFromCodeCoverage]
public bool IsCommandHelpOpen { get; set; }

Property Value

bool

IsConsoleFiltered

True while anything at all is being hidden, so the UI can offer to undo it.

public bool IsConsoleFiltered { get; }

Property Value

bool

IsCrossplayOn

Whether to show the Bedrock panel at all: the user asked for crossplay.

public bool IsCrossplayOn { get; }

Property Value

bool

Remarks

Deliberately not "we successfully looked a tunnel up", which is what the panel used to be tied to. Everything the user needs in the first minute — the local port, and the fact that the app is still waiting on playit — is knowable before any lookup succeeds, and hiding the whole block until one did is what made a working server look like a broken one.

IsModded

public bool IsModded { get; }

Property Value

bool

IsRunning

public bool IsRunning { get; }

Property Value

bool

KickPlayerCommand

Gets an IAsyncRelayCommand<T> instance wrapping KickPlayer(string).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<string?> KickPlayerCommand { get; }

Property Value

IAsyncRelayCommand<string>

KnownPlayers

Players who have ever joined (usercache.json).

public ObservableCollection<string> KnownPlayers { get; }

Property Value

ObservableCollection<string>

Mods

public ServerModsViewModel Mods { get; }

Property Value

ServerModsViewModel

MotdText

[ExcludeFromCodeCoverage]
public string MotdText { get; set; }

Property Value

string

Name

[ExcludeFromCodeCoverage]
public string Name { get; set; }

Property Value

string

NewWhitelistName

[ExcludeFromCodeCoverage]
public string NewWhitelistName { get; set; }

Property Value

string

OpPlayerCommand

Gets an IAsyncRelayCommand<T> instance wrapping OpPlayer(string).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<string?> OpPlayerCommand { get; }

Property Value

IAsyncRelayCommand<string>

OpPlayers

Operators (ops.json).

public ObservableCollection<string> OpPlayers { get; }

Property Value

ObservableCollection<string>

OpenPlayitDashboardCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.OpenPlayitDashboard().

[ExcludeFromCodeCoverage]
public IRelayCommand OpenPlayitDashboardCommand { get; }

Property Value

IRelayCommand

PardonPlayerCommand

Gets an IAsyncRelayCommand<T> instance wrapping PardonPlayer(string).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<string?> PardonPlayerCommand { get; }

Property Value

IAsyncRelayCommand<string>

PlayerCountText

[ExcludeFromCodeCoverage]
public string PlayerCountText { get; set; }

Property Value

string

PlayitState

[ExcludeFromCodeCoverage]
public PlayitState PlayitState { get; set; }

Property Value

PlayitState

PlayitStatusText

[ExcludeFromCodeCoverage]
public string PlayitStatusText { get; set; }

Property Value

string

PortText

[ExcludeFromCodeCoverage]
public string PortText { get; set; }

Property Value

string

RamSeries

[ExcludeFromCodeCoverage]
public IReadOnlyList<double>? RamSeries { get; set; }

Property Value

IReadOnlyList<double>

RamText

[ExcludeFromCodeCoverage]
public string RamText { get; set; }

Property Value

string

RefreshPlayersCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.RefreshPlayers().

[ExcludeFromCodeCoverage]
public IRelayCommand RefreshPlayersCommand { get; }

Property Value

IRelayCommand

RemoveFromWhitelistCommand

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<string?> RemoveFromWhitelistCommand { get; }

Property Value

IAsyncRelayCommand<string>

RestartCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.Restart().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand RestartCommand { get; }

Property Value

IAsyncRelayCommand

SendCommandCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.SendCommand().

[ExcludeFromCodeCoverage]
public IRelayCommand SendCommandCommand { get; }

Property Value

IRelayCommand

ServerIcon

[ExcludeFromCodeCoverage]
public Bitmap? ServerIcon { get; set; }

Property Value

Bitmap

ServerTypeBrush

Badge color per type (shared palette; unknown/future types fall back to gray).

public IBrush ServerTypeBrush { get; }

Property Value

IBrush

ServerTypeText

Server type shown as a badge (Vanilla/Fabric/Forge, and any future type).

public string ServerTypeText { get; }

Property Value

string

ShowAllConsoleKindsCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.ShowAllConsoleKinds().

[ExcludeFromCodeCoverage]
public IRelayCommand ShowAllConsoleKindsCommand { get; }

Property Value

IRelayCommand

ShowTunnelWarning

[ExcludeFromCodeCoverage]
public bool ShowTunnelWarning { get; set; }

Property Value

bool

SignalBrush

[ExcludeFromCodeCoverage]
public IBrush SignalBrush { get; set; }

Property Value

IBrush

SignalHint

[ExcludeFromCodeCoverage]
public string SignalHint { get; set; }

Property Value

string

StartCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.Start().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand StartCommand { get; }

Property Value

IAsyncRelayCommand

State

[ExcludeFromCodeCoverage]
public ServerState State { get; set; }

Property Value

ServerState

StatusBrush

[ExcludeFromCodeCoverage]
public IBrush StatusBrush { get; set; }

Property Value

IBrush

StatusText

[ExcludeFromCodeCoverage]
public string StatusText { get; set; }

Property Value

string

StopCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.Stop().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand StopCommand { get; }

Property Value

IAsyncRelayCommand

TogglePlayitCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerViewModel.TogglePlayit().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand TogglePlayitCommand { get; }

Property Value

IAsyncRelayCommand

TunnelAddress

[ExcludeFromCodeCoverage]
public string? TunnelAddress { get; set; }

Property Value

string

UptimeText

[ExcludeFromCodeCoverage]
public string UptimeText { get; set; }

Property Value

string

UseCommandCommand

Gets an IRelayCommand<T> instance wrapping UseCommand(CommandHelp).

[ExcludeFromCodeCoverage]
public IRelayCommand<CommandHelp?> UseCommandCommand { get; }

Property Value

IRelayCommand<CommandHelp>

VisibleConsoleLines

The lines currently shown in the console UI: all of ConsoleLines when nothing is filtered, or the matching subset (kept in order, updated incrementally as new lines arrive) while a search is typed or a category is switched off.

public BulkObservableCollection<ConsoleLine> VisibleConsoleLines { get; }

Property Value

BulkObservableCollection<ConsoleLine>

WhitelistEnabled

[ExcludeFromCodeCoverage]
public bool WhitelistEnabled { get; set; }

Property Value

bool

WhitelistPlayers

Players currently in the whitelist (names).

public ObservableCollection<string> WhitelistPlayers { get; }

Property Value

ObservableCollection<string>

Methods

CreateTunnelAsync(string)

Creates (if it doesn't exist) the Playit tunnel for this server's port, using the write key. Messages are shown in the server's console.

public Task CreateTunnelAsync(string writeKey)

Parameters

writeKey string

Returns

Task

RefreshConsoleColours()

Repaints the console and its switches after the colours change in the settings.

public void RefreshConsoleColours()

Remarks

The lines themselves get their colour through a converter, so nothing here has to hold a brush per line. Rebuilding the visible list is what makes them ask again: it is a single Reset, the items are re-created, and the converter runs with the new settings.

RefreshFromDisk()

Re-reads data from disk (after editing server.properties).

public void RefreshFromDisk()

SetUpBedrockModContentAsync()

Installs Hydraulic and Fabric API, so Bedrock players see what the mods add.

public Task SetUpBedrockModContentAsync()

Returns

Task

Remarks

The flag is only set once the install has actually succeeded. A server remembering it has this when the download failed would leave Bedrock players staring at invisible blocks with the app insisting it was handled.

SetUpCrossplayAsync(string?)

Installs Geyser and Floodgate, creates the Bedrock tunnel and points Geyser at it.

public Task SetUpCrossplayAsync(string? playitKey)

Parameters

playitKey string

Returns

Task

Remarks

The order matters. The tunnel has to exist before the config is written, because the one value Geyser cannot work out for itself is the tunnel's public port — and writing the config first would leave it advertising the wrong one until something happened to rewrite it.

SetUpMultiVersionAsync()

Installs ViaVersion and ViaBackwards, so other Minecraft versions can join.

public Task SetUpMultiVersionAsync()

Returns

Task

Remarks

Nothing to configure and no tunnel involved: both plugins work as installed. The flag is only set once the install has actually succeeded — a server remembering it has them when the download failed would turn players away and show no reason for it.

ShutdownAsync()

Stops the server when the app closes. Does NOT touch the Playit service (keeps running in the background).

public Task ShutdownAsync()

Returns

Task

Events

ConfigChanged

Raised when something persistable about the server changes (to save).

public event Action? ConfigChanged

Event Type

Action