mirror of
https://github.com/tribufu/ServerManagers
synced 2026-05-06 15:17:34 +00:00
- fixed the zip utils to read the file contents before backup. - added new content backup metho for support zip creation.
1098 lines
43 KiB
C#
1098 lines
43 KiB
C#
using ServerManagerTool.Common.Enums;
|
|
using ServerManagerTool.Common.Extensions;
|
|
using ServerManagerTool.Common.Lib;
|
|
using ServerManagerTool.Common.Utils;
|
|
using ServerManagerTool.Enums;
|
|
using ServerManagerTool.Lib;
|
|
using ServerManagerTool.Lib.ViewModel;
|
|
using ServerManagerTool.Lib.ViewModel.RCON;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Data;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using System.Windows.Interactivity;
|
|
using System.Windows.Media;
|
|
using WPFSharp.Globalizer;
|
|
|
|
namespace ServerManagerTool
|
|
{
|
|
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
|
|
public enum InputMode
|
|
{
|
|
Command,
|
|
Global,
|
|
Broadcast,
|
|
}
|
|
|
|
public enum InputWindowMode
|
|
{
|
|
None,
|
|
ServerChatTo,
|
|
RenamePlayer,
|
|
RenameTribe,
|
|
}
|
|
|
|
public class ScrollToBottomAction : TriggerAction<RichTextBox>
|
|
{
|
|
protected override void Invoke(object parameter)
|
|
{
|
|
AssociatedObject.ScrollToEnd();
|
|
}
|
|
}
|
|
|
|
public class RCONOutput_CommandTime : Run
|
|
{
|
|
public RCONOutput_CommandTime()
|
|
: this(DateTime.Now)
|
|
{
|
|
}
|
|
|
|
public RCONOutput_CommandTime(DateTime time)
|
|
: base($"[{time.ToString("g")}] ")
|
|
{
|
|
}
|
|
}
|
|
|
|
public class RCONOutput_TimedCommand : Span
|
|
{
|
|
protected RCONOutput_TimedCommand()
|
|
: base()
|
|
{
|
|
base.Inlines.Add(new RCONOutput_CommandTime());
|
|
}
|
|
|
|
public RCONOutput_TimedCommand(Inline output)
|
|
: this()
|
|
{
|
|
base.Inlines.Add(output);
|
|
}
|
|
|
|
public RCONOutput_TimedCommand(string output)
|
|
: this(new Run(output))
|
|
{
|
|
}
|
|
}
|
|
|
|
public class RCONOutput_Comment : Run
|
|
{
|
|
public RCONOutput_Comment(string value)
|
|
: base(value)
|
|
{
|
|
Foreground = Brushes.Green;
|
|
}
|
|
}
|
|
|
|
public class RCONOutput_ChatSend : RCONOutput_TimedCommand
|
|
{
|
|
public RCONOutput_ChatSend(string target, string output)
|
|
: base($"[{target}] {output}")
|
|
{
|
|
}
|
|
}
|
|
|
|
public class RCONOutput_Broadcast : RCONOutput_ChatSend
|
|
{
|
|
public RCONOutput_Broadcast(string output)
|
|
: base("ALL", output)
|
|
{
|
|
Foreground = Brushes.Orange;
|
|
}
|
|
}
|
|
|
|
public class RCONOutput_ConnectionChanged : RCONOutput_TimedCommand
|
|
{
|
|
public RCONOutput_ConnectionChanged(bool isConnected)
|
|
: base(isConnected ? GlobalizedApplication.Instance.GetResourceString("RCON_ConnectionEstablishedLabel") : GlobalizedApplication.Instance.GetResourceString("RCON_ConnectionLostLabel"))
|
|
{
|
|
Foreground = Brushes.Orange;
|
|
}
|
|
}
|
|
|
|
public class RCONOutput_Command : RCONOutput_TimedCommand
|
|
{
|
|
public RCONOutput_Command(string text)
|
|
: base(text)
|
|
{
|
|
}
|
|
};
|
|
|
|
public class RCONOutput_NoResponse : RCONOutput_TimedCommand
|
|
{
|
|
public RCONOutput_NoResponse()
|
|
: base(GlobalizedApplication.Instance.GetResourceString("RCON_NoCommandResponseLabel"))
|
|
{
|
|
Foreground = Brushes.LightGray;
|
|
}
|
|
};
|
|
|
|
public class RCONOutput_CommandOutput : RCONOutput_TimedCommand
|
|
{
|
|
public RCONOutput_CommandOutput(string text)
|
|
: base(text)
|
|
{
|
|
}
|
|
};
|
|
|
|
public class RCONOutput_PlayerJoined : RCONOutput_TimedCommand
|
|
{
|
|
public RCONOutput_PlayerJoined(string text)
|
|
: base(text)
|
|
{
|
|
Foreground = new SolidColorBrush(Color.FromArgb(255, 85, 142, 181));
|
|
}
|
|
};
|
|
|
|
public class RCONOutput_PlayerLeft : RCONOutput_TimedCommand
|
|
{
|
|
public RCONOutput_PlayerLeft(string text)
|
|
: base(text)
|
|
{
|
|
Foreground = new SolidColorBrush(Color.FromArgb(255, 62, 104, 132));
|
|
}
|
|
};
|
|
|
|
/// <summary>
|
|
/// Interaction logic for RCON.xaml
|
|
/// </summary>
|
|
public partial class RCONWindow : Window
|
|
{
|
|
private static Dictionary<Server, RCONWindow> RCONWindows = new Dictionary<Server, RCONWindow>();
|
|
|
|
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
|
|
|
public static readonly DependencyProperty CurrentConfigProperty = DependencyProperty.Register(nameof(CurrentConfig), typeof(Config), typeof(RCONWindow), new PropertyMetadata(Config.Default));
|
|
public static readonly DependencyProperty CurrentInputModeProperty = DependencyProperty.Register(nameof(CurrentInputMode), typeof(InputMode), typeof(RCONWindow), new PropertyMetadata(InputMode.Command));
|
|
public static readonly DependencyProperty PlayerFilteringProperty = DependencyProperty.Register(nameof(PlayerFiltering), typeof(PlayerFilterType), typeof(RCONWindow), new PropertyMetadata(PlayerFilterType.Online | PlayerFilterType.Offline | PlayerFilterType.Whitelisted));
|
|
public static readonly DependencyProperty PlayerFilterStringProperty = DependencyProperty.Register(nameof(PlayerFilterString), typeof(string), typeof(RCONWindow), new PropertyMetadata(string.Empty));
|
|
public static readonly DependencyProperty PlayerSortingProperty = DependencyProperty.Register(nameof(PlayerSorting), typeof(PlayerSortType), typeof(RCONWindow), new PropertyMetadata(PlayerSortType.Online));
|
|
public static readonly DependencyProperty PlayersViewProperty = DependencyProperty.Register(nameof(PlayersView), typeof(ICollectionView), typeof(RCONWindow), new PropertyMetadata(null));
|
|
public static readonly DependencyProperty RCONParametersProperty = DependencyProperty.Register(nameof(RCONParameters), typeof(RCONParameters), typeof(RCONWindow), new PropertyMetadata(null));
|
|
public static readonly DependencyProperty ScrollOnNewInputProperty = DependencyProperty.Register(nameof(ScrollOnNewInput), typeof(bool), typeof(RCONWindow), new PropertyMetadata(true));
|
|
public static readonly DependencyProperty ServerRCONProperty = DependencyProperty.Register(nameof(ServerRCON), typeof(ServerRcon), typeof(RCONWindow), new PropertyMetadata(null));
|
|
|
|
public RCONWindow(RCONParameters parameters)
|
|
{
|
|
InitializeComponent();
|
|
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
|
|
|
this.CurrentInputWindowMode = InputWindowMode.None;
|
|
this.PlayerFiltering = (PlayerFilterType)Config.Default.RCON_PlayerListFilter;
|
|
this.PlayerSorting = (PlayerSortType)Config.Default.RCON_PlayerListSort;
|
|
this.RCONParameters = parameters;
|
|
this.ServerRCON = new ServerRcon(parameters);
|
|
this.ServerRCON.RegisterCommandListener(RenderRCONCommandOutput);
|
|
this.ServerRCON.Players.CollectionChanged += Players_CollectionChanged;
|
|
this.ServerRCON.PlayersCollectionUpdated += Players_CollectionUpdated;
|
|
|
|
this.PlayersView = CollectionViewSource.GetDefaultView(this.ServerRCON.Players);
|
|
this.PlayersView.Filter = new Predicate<object>(PlayerFilter);
|
|
|
|
var notifier = new PropertyChangeNotifier(this.ServerRCON, ServerRcon.StatusProperty, (o, e) =>
|
|
{
|
|
this.RenderConnectionStateChange(e);
|
|
});
|
|
|
|
if (this.RCONParameters?.Server?.Runtime != null)
|
|
{
|
|
this.RCONParameters.Server.Runtime.StatusUpdate += Runtime_StatusUpdate;
|
|
}
|
|
|
|
if (this.RCONParameters?.Server == null)
|
|
{
|
|
this.PlayerCountSeparator.Visibility = Visibility.Collapsed;
|
|
this.MaxPlayerLabel.Visibility = Visibility.Collapsed;
|
|
}
|
|
|
|
this.ServerRCON.Initialize();
|
|
|
|
this.DataContext = this;
|
|
|
|
RenderCommentsBlock(
|
|
_globalizer.GetResourceString("RCON_Comments_Line1"),
|
|
_globalizer.GetResourceString("RCON_Comments_Line2"),
|
|
_globalizer.GetResourceString("RCON_Comments_Line3"),
|
|
_globalizer.GetResourceString("RCON_Comments_Line4"),
|
|
_globalizer.GetResourceString("RCON_Comments_Line5"),
|
|
String.Format(_globalizer.GetResourceString("RCON_Comments_Line6"),
|
|
_globalizer.GetResourceString("RCON_Help_Keyword")));
|
|
|
|
if (this.RCONParameters.WindowExtents.Width > 50 && this.RCONParameters.WindowExtents.Height > 50)
|
|
{
|
|
this.Left = this.RCONParameters.WindowExtents.Left;
|
|
this.Top = this.RCONParameters.WindowExtents.Top;
|
|
this.Width = this.RCONParameters.WindowExtents.Width;
|
|
this.Height = this.RCONParameters.WindowExtents.Height;
|
|
|
|
//
|
|
// Fix issues where the console was saved while offscreen.
|
|
if(this.Left == -32000)
|
|
{
|
|
this.Left = 0;
|
|
}
|
|
|
|
if(this.Top == -32000)
|
|
{
|
|
this.Top = 0;
|
|
}
|
|
}
|
|
|
|
SetPlayerListWidth(this.RCONParameters.PlayerListWidth);
|
|
|
|
this.ConsoleInput.Focus();
|
|
|
|
// hook into the language change event
|
|
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
|
|
}
|
|
|
|
#region Properties
|
|
public Config CurrentConfig
|
|
{
|
|
get { return (Config)GetValue(CurrentConfigProperty); }
|
|
set { SetValue(CurrentConfigProperty, value); }
|
|
}
|
|
|
|
public InputMode CurrentInputMode
|
|
{
|
|
get { return (InputMode)GetValue(CurrentInputModeProperty); }
|
|
set { SetValue(CurrentInputModeProperty, value); }
|
|
}
|
|
|
|
public PlayerFilterType PlayerFiltering
|
|
{
|
|
get { return (PlayerFilterType)GetValue(PlayerFilteringProperty); }
|
|
set { SetValue(PlayerFilteringProperty, value); }
|
|
}
|
|
|
|
public string PlayerFilterString
|
|
{
|
|
get { return (string)GetValue(PlayerFilterStringProperty); }
|
|
set { SetValue(PlayerFilterStringProperty, value); }
|
|
}
|
|
|
|
public PlayerSortType PlayerSorting
|
|
{
|
|
get { return (PlayerSortType)GetValue(PlayerSortingProperty); }
|
|
set { SetValue(PlayerSortingProperty, value); }
|
|
}
|
|
|
|
public ICollectionView PlayersView
|
|
{
|
|
get { return (ICollectionView)GetValue(PlayersViewProperty); }
|
|
set { SetValue(PlayersViewProperty, value); }
|
|
}
|
|
|
|
public RCONParameters RCONParameters
|
|
{
|
|
get { return (RCONParameters)GetValue(RCONParametersProperty); }
|
|
set { SetValue(RCONParametersProperty, value); }
|
|
}
|
|
|
|
public bool ScrollOnNewInput
|
|
{
|
|
get { return (bool)GetValue(ScrollOnNewInputProperty); }
|
|
set { SetValue(ScrollOnNewInputProperty, value); }
|
|
}
|
|
|
|
public ServerRcon ServerRCON
|
|
{
|
|
get { return (ServerRcon)GetValue(ServerRCONProperty); }
|
|
set { SetValue(ServerRCONProperty, value); }
|
|
}
|
|
#endregion
|
|
|
|
#region Commands
|
|
private InputWindowMode CurrentInputWindowMode
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public ICommand Button1Command
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<object>(
|
|
execute: (_) =>
|
|
{
|
|
inputBox.Visibility = Visibility.Collapsed;
|
|
dockPanel.IsEnabled = true;
|
|
|
|
PlayerInfo player;
|
|
var inputText = inputTextBox.Text;
|
|
|
|
switch (this.CurrentInputWindowMode)
|
|
{
|
|
case InputWindowMode.ServerChatTo:
|
|
player = inputBox.Tag as PlayerInfo;
|
|
if (player != null)
|
|
this.ServerRCON.IssueCommand($"ServerChatTo \"{player.PlayerId}\" {inputText}");
|
|
break;
|
|
|
|
case InputWindowMode.RenamePlayer:
|
|
player = inputBox.Tag as PlayerInfo;
|
|
if (player != null && player.PlayerData != null)
|
|
this.ServerRCON.IssueCommand($"RenamePlayer \"{player.CharacterName}\" {inputText}");
|
|
break;
|
|
|
|
case InputWindowMode.RenameTribe:
|
|
player = inputBox.Tag as PlayerInfo;
|
|
if (player != null)
|
|
this.ServerRCON.IssueCommand($"RenameTribe \"{player.TribeName}\" {inputText}");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Clear InputBox.
|
|
inputTextBox.Text = String.Empty;
|
|
this.CurrentInputWindowMode = InputWindowMode.None;
|
|
},
|
|
canExecute: (_) => true
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand Button2Command
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<object>(
|
|
execute: (_) =>
|
|
{
|
|
inputBox.Visibility = Visibility.Collapsed;
|
|
dockPanel.IsEnabled = true;
|
|
|
|
switch (this.CurrentInputWindowMode)
|
|
{
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Clear InputBox.
|
|
inputTextBox.Text = String.Empty;
|
|
this.CurrentInputWindowMode = InputWindowMode.None;
|
|
},
|
|
canExecute: (_) => true
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand ClearLogsCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<object>(
|
|
execute: (_) =>
|
|
{
|
|
string logsDir = String.Empty;
|
|
try
|
|
{
|
|
logsDir = App.GetProfileLogFolder(this.RCONParameters.ProfileId);
|
|
Directory.Delete(logsDir, true);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Ignore any failures here, best effort only.
|
|
}
|
|
|
|
MessageBox.Show(String.Format(_globalizer.GetResourceString("RCON_ClearLogs_Label"), logsDir), _globalizer.GetResourceString("RCON_ClearLogs_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
|
|
},
|
|
canExecute: (_) => this.RCONParameters.Server != null
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand ViewLogsCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<object>(
|
|
execute: (_) =>
|
|
{
|
|
string logsDir = String.Empty;
|
|
try
|
|
{
|
|
logsDir = App.GetProfileLogFolder(this.RCONParameters.ProfileId);
|
|
Process.Start(logsDir);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
MessageBox.Show(String.Format(_globalizer.GetResourceString("RCON_ViewLogs_ErrorLabel"), logsDir, ex.Message), _globalizer.GetResourceString("RCON_ViewLogs_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
},
|
|
canExecute: (_) => this.RCONParameters.Server != null
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand SaveWorldCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<object>(
|
|
execute: (_) =>
|
|
{
|
|
var message = _globalizer.GetResourceString("RCON_SaveWorldLabel");
|
|
this.ServerRCON.IssueCommand($"{Config.Default.RCON_MessageCommand.ToLower()} {message}");
|
|
|
|
this.ServerRCON.IssueCommand(Config.Default.ServerSaveCommand);
|
|
},
|
|
canExecute: (_) => true
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand DestroyWildDinosCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<object>(
|
|
execute: (_) =>
|
|
{
|
|
var message = _globalizer.GetResourceString("RCON_DestroyWildDinosLabel");
|
|
this.ServerRCON.IssueCommand($"{Config.Default.RCON_MessageCommand.ToLower()} {message}");
|
|
|
|
this.ServerRCON.IssueCommand(ServerRcon.RCON_COMMAND_WILDDINOWIPE);
|
|
},
|
|
canExecute: (_) => true
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand SortPlayersCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerSortType>(
|
|
execute: (sort) =>
|
|
{
|
|
Config.Default.RCON_PlayerListSort = (int)this.PlayerSorting;
|
|
SortPlayers();
|
|
},
|
|
canExecute: (sort) => true
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand FilterPlayersCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerFilterType>(
|
|
execute: (filter) =>
|
|
{
|
|
this.PlayerFiltering ^= filter;
|
|
Config.Default.RCON_PlayerListFilter = (int)this.PlayerFiltering;
|
|
this.PlayersView.Refresh();
|
|
},
|
|
canExecute: (filter) => true
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand ChatPlayerCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerInfo>(
|
|
execute: (player) =>
|
|
{
|
|
dockPanel.IsEnabled = false;
|
|
|
|
CurrentInputWindowMode = InputWindowMode.ServerChatTo;
|
|
inputBox.Tag = player;
|
|
inputTitle.Text = $"{_globalizer.GetResourceString("RCON_ChatPlayerLabel")} {player.PlayerName ?? _globalizer.GetResourceString("RCON_UnnamedLabel")}";
|
|
inputTextBox.Text = string.Empty;
|
|
button1.Content = _globalizer.GetResourceString("RCON_Button_Send");
|
|
button2.Content = _globalizer.GetResourceString("RCON_Button_Cancel");
|
|
inputBox.Visibility = Visibility.Visible;
|
|
},
|
|
canExecute: (player) => player != null && player.IsValid && player.IsOnline
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand RenamePlayerCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerInfo>(
|
|
execute: (player) =>
|
|
{
|
|
dockPanel.IsEnabled = false;
|
|
|
|
CurrentInputWindowMode = InputWindowMode.RenamePlayer;
|
|
inputBox.Tag = player;
|
|
inputTitle.Text = $"{_globalizer.GetResourceString("RCON_RenamePlayerLabel")} {player.CharacterName ?? _globalizer.GetResourceString("RCON_UnnamedLabel")}";
|
|
inputTextBox.Text = string.Empty;
|
|
button1.Content = _globalizer.GetResourceString("RCON_Button_Change");
|
|
button2.Content = _globalizer.GetResourceString("RCON_Button_Cancel");
|
|
inputBox.Visibility = System.Windows.Visibility.Visible;
|
|
},
|
|
canExecute: (player) => player?.PlayerData != null && player.IsValid && player.IsOnline
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand RenameTribeCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerInfo>(
|
|
execute: (player) =>
|
|
{
|
|
dockPanel.IsEnabled = false;
|
|
|
|
CurrentInputWindowMode = InputWindowMode.RenameTribe;
|
|
inputBox.Tag = player;
|
|
inputTitle.Text = $"{_globalizer.GetResourceString("RCON_RenameTribeLabel")} {player.TribeName ?? _globalizer.GetResourceString("RCON_UnnamedLabel")}";
|
|
inputTextBox.Text = string.Empty;
|
|
button1.Content = _globalizer.GetResourceString("RCON_Button_Change");
|
|
button2.Content = _globalizer.GetResourceString("RCON_Button_Cancel");
|
|
inputBox.Visibility = System.Windows.Visibility.Visible;
|
|
},
|
|
canExecute: (player) => player != null && player.IsValid && player.IsOnline
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand ViewPlayerProfileCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerInfo>(
|
|
execute: (player) => {
|
|
var savedArksPath = ServerProfile.GetProfileSavePath(this.RCONParameters.InstallDirectory, this.RCONParameters.AltSaveDirectoryName, this.RCONParameters.PGM_Enabled, this.RCONParameters.PGM_Name);
|
|
var window = new PlayerProfileWindow(player, savedArksPath);
|
|
window.Owner = this;
|
|
window.ShowDialog();
|
|
},
|
|
canExecute: (player) => player?.PlayerData != null
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand ViewPlayerTribeCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerInfo>(
|
|
execute: (player) => {
|
|
var savedArksPath = ServerProfile.GetProfileSavePath(this.RCONParameters.InstallDirectory, this.RCONParameters.AltSaveDirectoryName, this.RCONParameters.PGM_Enabled, this.RCONParameters.PGM_Name);
|
|
var window = new TribeProfileWindow(player, this.ServerRCON.Players, savedArksPath);
|
|
window.Owner = this;
|
|
window.ShowDialog();
|
|
},
|
|
canExecute: (player) => player?.PlayerData != null && !string.IsNullOrWhiteSpace(player.TribeName)
|
|
);
|
|
}
|
|
}
|
|
|
|
public ICommand CopyIDCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerInfo>(
|
|
execute: (player) =>
|
|
{
|
|
try
|
|
{
|
|
System.Windows.Clipboard.SetText(player.PlayerId.ToString());
|
|
MessageBox.Show($"{_globalizer.GetResourceString("RCON_CopyIdLabel")} {player.PlayerName}", _globalizer.GetResourceString("RCON_CopyIdTitle"), MessageBoxButton.OK);
|
|
}
|
|
catch
|
|
{
|
|
MessageBox.Show($"{_globalizer.GetResourceString("RCON_ClipboardErrorLabel")}", _globalizer.GetResourceString("RCON_ClipboardErrorTitle"), MessageBoxButton.OK);
|
|
}
|
|
},
|
|
canExecute: (player) => player != null
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
public ICommand CopyPlayerIDCommand
|
|
{
|
|
get
|
|
{
|
|
return new RelayCommand<PlayerInfo>(
|
|
execute: (player) =>
|
|
{
|
|
if (player.PlayerData != null)
|
|
{
|
|
try
|
|
{
|
|
System.Windows.Clipboard.SetText(player.PlayerData.CharacterId.ToString());
|
|
MessageBox.Show($"{_globalizer.GetResourceString("RCON_CopyPlayerIdLabel")} {player.CharacterName}", _globalizer.GetResourceString("RCON_CopyPlayerIdTitle"), MessageBoxButton.OK);
|
|
}
|
|
catch
|
|
{
|
|
MessageBox.Show($"{_globalizer.GetResourceString("RCON_ClipboardErrorLabel")}", _globalizer.GetResourceString("RCON_ClipboardErrorTitle"), MessageBoxButton.OK);
|
|
}
|
|
}
|
|
},
|
|
canExecute: (player) => player?.PlayerData != null && player.IsValid
|
|
);
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Events
|
|
public static RCONWindow GetRCONForServer(Server server)
|
|
{
|
|
RCONWindow window;
|
|
if (!RCONWindows.TryGetValue(server, out window) || !window.IsLoaded)
|
|
{
|
|
window = new RCONWindow(new RCONParameters()
|
|
{
|
|
WindowTitle = String.Format(GlobalizedApplication.Instance.GetResourceString("RCON_TitleLabel"), server.Runtime.ProfileSnapshot.ProfileName),
|
|
WindowExtents = server.Profile.RCONWindowExtents,
|
|
PlayerListWidth = server.Profile.RCONPlayerListWidth,
|
|
|
|
Server = server,
|
|
InstallDirectory = server.Runtime.ProfileSnapshot.InstallDirectory,
|
|
AltSaveDirectoryName = server.Runtime.ProfileSnapshot.AltSaveDirectoryName,
|
|
ProfileId = server.Runtime.ProfileSnapshot.ProfileId,
|
|
ProfileName = server.Runtime.ProfileSnapshot.ProfileName,
|
|
MaxPlayers = server.Runtime.MaxPlayers,
|
|
RCONHost = server.Runtime.ProfileSnapshot.ServerIPAddress.ToString(),
|
|
RCONPort = server.Runtime.ProfileSnapshot.RCONPort,
|
|
RCONPassword = server.Runtime.ProfileSnapshot.RCONPassword,
|
|
|
|
PGM_Enabled = server.Profile.PGM_Enabled,
|
|
PGM_Name = server.Profile.PGM_Name,
|
|
});
|
|
RCONWindows[server] = window;
|
|
}
|
|
|
|
return window;
|
|
}
|
|
|
|
public static RCONWindow GetRCON(RCONParameters parameters)
|
|
{
|
|
return new RCONWindow(parameters);
|
|
}
|
|
|
|
private void ResourceDictionaryChangedEvent(object source, ResourceDictionaryChangedEventArgs e)
|
|
{
|
|
// refresh the InputModes combobox list
|
|
this.InputModesComboBox.Items.Refresh();
|
|
|
|
// refresh the InputModes combobox value
|
|
var currentInputMode = CurrentInputMode;
|
|
this.InputModesComboBox.SelectedItem = null;
|
|
this.InputModesComboBox.SelectedItem = currentInputMode;
|
|
}
|
|
|
|
protected override void OnClosed(EventArgs e)
|
|
{
|
|
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent -= ResourceDictionaryChangedEvent;
|
|
|
|
if (this.RCONParameters?.Server?.Runtime != null)
|
|
{
|
|
this.RCONParameters.Server.Runtime.StatusUpdate -= Runtime_StatusUpdate;
|
|
}
|
|
|
|
base.OnClosed(e);
|
|
}
|
|
|
|
protected override void OnClosing(CancelEventArgs e)
|
|
{
|
|
this.ServerRCON.PlayersCollectionUpdated -= Players_CollectionUpdated;
|
|
this.ServerRCON.Players.CollectionChanged -= Players_CollectionChanged;
|
|
this.ServerRCON.DisposeAsync().DoNotWait();
|
|
|
|
if (this.RCONParameters?.Server != null)
|
|
{
|
|
RCONWindows.TryGetValue(this.RCONParameters.Server, out RCONWindow window);
|
|
if (window != null)
|
|
RCONWindows.Remove(this.RCONParameters.Server);
|
|
}
|
|
|
|
base.OnClosing(e);
|
|
}
|
|
|
|
private void RCON_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
{
|
|
if (this.WindowState == WindowState.Normal)
|
|
{
|
|
Rect savedRect = this.RCONParameters.WindowExtents;
|
|
this.RCONParameters.WindowExtents = new Rect(savedRect.Location, e.NewSize);
|
|
if (this.RCONParameters.Server != null)
|
|
{
|
|
this.RCONParameters.Server.Profile.RCONWindowExtents = this.RCONParameters.WindowExtents;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RCON_LocationChanged(object sender, EventArgs e)
|
|
{
|
|
if (this.WindowState != WindowState.Minimized && this.Left != -32000 && this.Top != -32000)
|
|
{
|
|
Rect savedRect = this.RCONParameters.WindowExtents;
|
|
this.RCONParameters.WindowExtents = new Rect(new Point(this.Left, this.Top), savedRect.Size);
|
|
if (this.RCONParameters.Server != null)
|
|
{
|
|
this.RCONParameters.Server.Profile.RCONWindowExtents = this.RCONParameters.WindowExtents;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ConsoleInput_KeyUp(object sender, KeyEventArgs e)
|
|
{
|
|
if(e.Key == Key.Enter)
|
|
{
|
|
var textBox = (TextBox)sender;
|
|
var effectiveMode = this.CurrentInputMode;
|
|
var commandText = textBox.Text.Trim();
|
|
if (commandText.StartsWith(_globalizer.GetResourceString("RCON_Help_Keyword")))
|
|
{
|
|
RenderCommentsBlock(
|
|
_globalizer.GetResourceString("RCON_Help_Line1"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line2"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line3"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line4"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line5"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line6"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line7"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line8"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line9"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line10"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line11"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line12"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line13"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line14"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line15"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line16"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line17"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line18"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line19"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line20"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line21"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line22"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line23"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line24"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line25"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line26"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line27"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line28"),
|
|
_globalizer.GetResourceString("RCON_Help_Line29"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line30"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line31"),
|
|
" " + _globalizer.GetResourceString("RCON_Help_Line32")
|
|
);
|
|
}
|
|
else
|
|
{
|
|
if (commandText.StartsWith("/"))
|
|
{
|
|
effectiveMode = InputMode.Command;
|
|
commandText = commandText.Substring(1);
|
|
}
|
|
|
|
switch (effectiveMode)
|
|
{
|
|
case InputMode.Command:
|
|
this.ServerRCON.IssueCommand(commandText);
|
|
break;
|
|
|
|
case InputMode.Broadcast:
|
|
this.ServerRCON.IssueCommand($"{ServerRcon.RCON_COMMAND_BROADCAST} {commandText}");
|
|
break;
|
|
|
|
case InputMode.Global:
|
|
if (!String.IsNullOrWhiteSpace(Config.Default.RCON_AdminName))
|
|
{
|
|
this.ServerRCON.IssueCommand($"{ServerRcon.RCON_COMMAND_SERVERCHAT} [{Config.Default.RCON_AdminName}] {commandText}");
|
|
}
|
|
else
|
|
{
|
|
this.ServerRCON.IssueCommand($"{ServerRcon.RCON_COMMAND_SERVERCHAT} {commandText}");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
textBox.Text = String.Empty;
|
|
}
|
|
}
|
|
|
|
private void Players_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
SortPlayers();
|
|
this.PlayersView?.Refresh();
|
|
}
|
|
|
|
private void Players_CollectionUpdated(object sender, EventArgs e)
|
|
{
|
|
this.PlayersView = CollectionViewSource.GetDefaultView(this.ServerRCON.Players);
|
|
this.PlayersView.Filter = new Predicate<object>(PlayerFilter);
|
|
|
|
SortPlayers();
|
|
this.PlayersView?.Refresh();
|
|
}
|
|
|
|
private void PlayerList_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
{
|
|
this.RCONParameters.PlayerListWidth = this.playerListColumn.Width.Value;
|
|
if (this.RCONParameters.Server != null)
|
|
{
|
|
this.RCONParameters.Server.Profile.RCONPlayerListWidth = this.RCONParameters.PlayerListWidth;
|
|
}
|
|
}
|
|
|
|
private void Runtime_StatusUpdate(object sender, EventArgs e)
|
|
{
|
|
this.RCONParameters.ProfileName = this.RCONParameters?.Server?.Runtime?.ProfileSnapshot.ProfileName ?? "<unknown>";
|
|
this.RCONParameters.MaxPlayers = this.RCONParameters?.Server?.Runtime?.MaxPlayers ?? 0;
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
public static void CloseAllWindows()
|
|
{
|
|
var windows = RCONWindows.Values.ToList();
|
|
foreach (var window in windows)
|
|
{
|
|
if (window.IsLoaded)
|
|
window.Close();
|
|
}
|
|
windows.Clear();
|
|
}
|
|
|
|
private void SetPlayerListWidth(double value)
|
|
{
|
|
if (value < this.playerListColumn.MinWidth)
|
|
this.playerListColumn.Width = new GridLength(this.playerListColumn.MinWidth, GridUnitType.Pixel);
|
|
else
|
|
this.playerListColumn.Width = new GridLength(value, GridUnitType.Pixel);
|
|
}
|
|
|
|
public void SortPlayers()
|
|
{
|
|
this.PlayersView.SortDescriptions.Clear();
|
|
|
|
switch (this.PlayerSorting)
|
|
{
|
|
case PlayerSortType.Name:
|
|
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
|
break;
|
|
|
|
case PlayerSortType.Online:
|
|
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.IsOnline), ListSortDirection.Descending));
|
|
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
|
break;
|
|
|
|
case PlayerSortType.Tribe:
|
|
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.TribeName), ListSortDirection.Ascending));
|
|
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
|
break;
|
|
|
|
case PlayerSortType.LastUpdated:
|
|
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.LastUpdated), ListSortDirection.Descending));
|
|
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
|
break;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Command Methods
|
|
private void AddBlockContent(Block b)
|
|
{
|
|
ConsoleContent.Blocks.Add(b);
|
|
}
|
|
|
|
private IEnumerable<Inline> FormatCommandInput(ConsoleCommand command)
|
|
{
|
|
if (command.command.Equals(ServerRcon.RCON_COMMAND_BROADCAST, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
yield return new RCONOutput_Broadcast(command.args);
|
|
}
|
|
else
|
|
{
|
|
yield return new RCONOutput_Command($"> {command.rawCommand}");
|
|
}
|
|
|
|
if(!command.suppressOutput && !command.lines.IsEmpty())
|
|
{
|
|
yield return new LineBreak();
|
|
}
|
|
}
|
|
|
|
private IEnumerable<Inline> FormatCommandOutput(ConsoleCommand command)
|
|
{
|
|
bool firstLine = true;
|
|
|
|
if (command.command.Equals(ServerRcon.RCON_COMMAND_LISTPLAYERS, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
foreach (var output in command.lines)
|
|
{
|
|
var trimmed = output.TrimEnd();
|
|
|
|
if (!firstLine)
|
|
{
|
|
yield return new LineBreak();
|
|
}
|
|
firstLine = false;
|
|
|
|
if (trimmed == ServerRcon.NoResponseOutput)
|
|
{
|
|
yield return new RCONOutput_NoResponse();
|
|
}
|
|
else if (trimmed.EndsWith("joined the game."))
|
|
{
|
|
yield return new RCONOutput_PlayerJoined(trimmed);
|
|
}
|
|
else if (trimmed.EndsWith("left the game."))
|
|
{
|
|
yield return new RCONOutput_PlayerLeft(trimmed);
|
|
}
|
|
else
|
|
{
|
|
yield return new RCONOutput_CommandOutput(trimmed);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (var output in command.lines)
|
|
{
|
|
var trimmed = output.TrimEnd();
|
|
|
|
if (!firstLine)
|
|
{
|
|
yield return new LineBreak();
|
|
}
|
|
firstLine = false;
|
|
|
|
if (trimmed == ServerRcon.NoResponseOutput)
|
|
{
|
|
yield return new RCONOutput_NoResponse();
|
|
}
|
|
else
|
|
{
|
|
yield return new RCONOutput_CommandOutput(trimmed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RenderCommentsBlock(params string[] lines)
|
|
{
|
|
var p = new Paragraph();
|
|
bool firstLine = true;
|
|
|
|
foreach (var output in lines)
|
|
{
|
|
var trimmed = output.TrimEnd();
|
|
|
|
if (!firstLine)
|
|
{
|
|
p.Inlines.Add(new LineBreak());
|
|
}
|
|
firstLine = false;
|
|
|
|
p.Inlines.Add(new RCONOutput_Comment(trimmed));
|
|
}
|
|
|
|
AddBlockContent(p);
|
|
}
|
|
|
|
private void RenderConnectionStateChange(DependencyPropertyChangedEventArgs e)
|
|
{
|
|
var oldStatus = (ConsoleStatus)e.OldValue;
|
|
var newStatus = (ConsoleStatus)e.NewValue;
|
|
|
|
if(oldStatus != newStatus)
|
|
{
|
|
var p = new Paragraph();
|
|
if (newStatus == ConsoleStatus.Connected)
|
|
{
|
|
p.Inlines.Add(new RCONOutput_ConnectionChanged(true));
|
|
}
|
|
else
|
|
{
|
|
p.Inlines.Add(new RCONOutput_ConnectionChanged(false));
|
|
}
|
|
|
|
AddBlockContent(p);
|
|
}
|
|
}
|
|
|
|
private void RenderRCONCommandOutput(ConsoleCommand command)
|
|
{
|
|
//
|
|
// Format output
|
|
//
|
|
var p = new Paragraph();
|
|
|
|
if (!command.suppressCommand)
|
|
{
|
|
foreach (var element in FormatCommandInput(command))
|
|
{
|
|
p.Inlines.Add(element);
|
|
}
|
|
}
|
|
|
|
if (!command.suppressOutput)
|
|
{
|
|
foreach (var element in FormatCommandOutput(command))
|
|
{
|
|
p.Inlines.Add(element);
|
|
}
|
|
}
|
|
|
|
if (!(command.suppressCommand && command.suppressOutput))
|
|
{
|
|
if (p.Inlines.Count > 0)
|
|
{
|
|
AddBlockContent(p);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Filtering
|
|
private void FilterPlayerList_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
this.PlayersView?.Refresh();
|
|
}
|
|
|
|
public bool PlayerFilter(object obj)
|
|
{
|
|
var player = obj as PlayerInfo;
|
|
if (player == null)
|
|
return false;
|
|
|
|
var result = (this.PlayerFiltering.HasFlag(PlayerFilterType.Online) && player.IsOnline) ||
|
|
(this.PlayerFiltering.HasFlag(PlayerFilterType.Offline) && !player.IsOnline) ||
|
|
(this.PlayerFiltering.HasFlag(PlayerFilterType.Admin) && player.IsAdmin) ||
|
|
(this.PlayerFiltering.HasFlag(PlayerFilterType.Whitelisted) && player.IsWhitelisted) ||
|
|
(this.PlayerFiltering.HasFlag(PlayerFilterType.Invalid) && !player.IsValid);
|
|
if (!result)
|
|
return false;
|
|
|
|
var filterString = PlayerFilterString.ToLower();
|
|
|
|
if (string.IsNullOrWhiteSpace(filterString))
|
|
return true;
|
|
|
|
result = player.PlayerNameFilterString != null && player.PlayerNameFilterString.Contains(filterString) ||
|
|
player.TribeNameFilterString != null && player.TribeNameFilterString.Contains(filterString) ||
|
|
player.CharacterNameFilterString != null && player.CharacterNameFilterString.Contains(filterString);
|
|
|
|
return result;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|