Showing preview only (259K chars total). Download the full file or copy to clipboard to get everything.
Repository: zkhssb/NectarRCON
Branch: master
Commit: e7349a9bd853
Files: 112
Total size: 224.2 KB
Directory structure:
gitextract_0vsxp36e/
├── .gitattributes
├── .github/
│ └── workflows/
│ └── dotnet-desktop.yml
├── .gitignore
├── LICENSE.txt
├── NectarRCON/
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AssemblyInfo.cs
│ ├── Converters/
│ │ ├── BoolToVisibilityConverter.cs
│ │ └── IntToVisibilityConverter.cs
│ ├── Dp/
│ │ ├── DpFile.cs
│ │ └── RconSettingsDp.cs
│ ├── Entity/
│ │ ├── ClearLogValueMessage.cs
│ │ ├── Config.cs
│ │ ├── ETheme.cs
│ │ ├── Group.cs
│ │ ├── MainPageLoadValueMessage.cs
│ │ ├── ServerInformation.cs
│ │ └── ServerPassword.cs
│ ├── Interfaces/
│ │ ├── IConfigService.cs
│ │ ├── IConnectingDialogService.cs
│ │ ├── IGroupService.cs
│ │ ├── IHistoryService.cs
│ │ ├── ILanguageService.cs
│ │ ├── ILogService.cs
│ │ ├── IMessageBoxService.cs
│ │ ├── IRconConnectionInfoService.cs
│ │ ├── IServerInformationService.cs
│ │ └── IServerPasswordService.cs
│ ├── Models/
│ │ ├── GroupModel.cs
│ │ ├── GroupServerItemModel.cs
│ │ └── ServerModel.cs
│ ├── NectarRCON.csproj
│ ├── Rcon/
│ │ ├── IRconConnection.cs
│ │ ├── RconMultiConnection.cs
│ │ └── RconSingleConnection.cs
│ ├── Resources/
│ │ └── Languages/
│ │ ├── en_us.xaml
│ │ ├── zh_cn.xaml
│ │ └── zh_tw.xaml
│ ├── Services/
│ │ ├── ApplicationHostService.cs
│ │ ├── ConfigService.cs
│ │ ├── ConnectingDialogService.cs
│ │ ├── GroupService.cs
│ │ ├── HistoryService.cs
│ │ ├── LanguageService.cs
│ │ ├── LogService.cs
│ │ ├── MessageBoxService.cs
│ │ ├── RconConnectionInfoService.cs
│ │ ├── ServerInformationService.cs
│ │ └── ServerPasswordService.cs
│ ├── ViewModels/
│ │ ├── AboutPageViewModel.cs
│ │ ├── AddGroupPageViewModel.cs
│ │ ├── AddServerWindowViewModel.cs
│ │ ├── EditPasswordWindowViewModel.cs
│ │ ├── EditServerWindowViewModel.cs
│ │ ├── GroupPageViewModel.cs
│ │ ├── JoinGroupWindowViewModel.cs
│ │ ├── MainPageViewModel.cs
│ │ ├── MainWindowViewModel.cs
│ │ ├── ServersPageViewModel.cs
│ │ └── SettingPageViewModel.cs
│ ├── Views/
│ │ └── Pages/
│ │ ├── AboutPage.xaml
│ │ ├── AboutPage.xaml.cs
│ │ ├── AddGroupPage.xaml
│ │ ├── AddGroupPage.xaml.cs
│ │ ├── GroupPage.xaml
│ │ ├── GroupPage.xaml.cs
│ │ ├── MainPage.xaml
│ │ ├── MainPage.xaml.cs
│ │ ├── ServersPage.xaml
│ │ ├── ServersPage.xaml.cs
│ │ ├── SettingPage.xaml
│ │ └── SettingPage.xaml.cs
│ ├── Windows/
│ │ ├── AddServerWindow.xaml
│ │ ├── AddServerWindow.xaml.cs
│ │ ├── EditPasswordWindow.xaml
│ │ ├── EditPasswordWindow.xaml.cs
│ │ ├── EditServerWindow.xaml
│ │ ├── EditServerWindow.xaml.cs
│ │ ├── JoinGroupWindow.xaml
│ │ ├── JoinGroupWindow.xaml.cs
│ │ ├── MainWindow.xaml
│ │ └── MainWindow.xaml.cs
│ └── app.manifest
├── NectarRCON.Adapter.Minecraft/
│ ├── MinecraftRconClient.cs
│ ├── NectarRCON.Adapter.Minecraft.csproj
│ ├── Packet.cs
│ ├── PacketEncoder.cs
│ └── README.md
├── NectarRCON.Core/
│ ├── Helper/
│ │ ├── AdapterHelpers.cs
│ │ ├── DNSHelpers.cs
│ │ └── Win32Helper.cs
│ └── NectarRCON.Core.csproj
├── NectarRCON.Export/
│ ├── Client/
│ │ └── BaseTcpClient.cs
│ ├── Interfaces/
│ │ ├── IRconAdapter.cs
│ │ └── IRconClient.cs
│ └── NectarRCON.Export.csproj
├── NectarRCON.Tests/
│ ├── Adapter/
│ │ └── MinecraftRconTest.cs
│ ├── DNSHelperTests.cs
│ ├── GroupServiceTests.cs
│ ├── MessageBoxServiceTests.cs
│ ├── NectarRCON.Tests.csproj
│ ├── UpdaterTests.cs
│ └── Usings.cs
├── NectarRCON.Updater/
│ ├── AppVersion.cs
│ ├── GithubUpdater.cs
│ ├── IUpdater.cs
│ ├── Model/
│ │ ├── Asset.cs
│ │ └── Release.cs
│ └── NectarRCON.Updater.csproj
├── NectarRCON.sln
├── README.md
└── README_EN.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
================================================
FILE: .github/workflows/dotnet-desktop.yml
================================================
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build, test, sign and package a WPF or Windows Forms desktop application
# built on .NET Core.
# To learn how to migrate your existing application to .NET Core,
# refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework
#
# To configure this workflow:
#
# 1. Configure environment variables
# GitHub sets default environment variables for every workflow run.
# Replace the variables relative to your project in the "env" section below.
#
# 2. Signing
# Generate a signing certificate in the Windows Application
# Packaging Project or add an existing signing certificate to the project.
# Next, use PowerShell to encode the .pfx file using Base64 encoding
# by running the following Powershell script to generate the output string:
#
# $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte
# [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt'
#
# Open the output file, SigningCertificate_Encoded.txt, and copy the
# string inside. Then, add the string to the repo as a GitHub secret
# and name it "Base64_Encoded_Pfx."
# For more information on how to configure your signing certificate for
# this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing
#
# Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key".
# See "Build the Windows Application Packaging project" below to see how the secret is used.
#
# For more information on GitHub Actions, refer to https://github.com/features/actions
# For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications,
# refer to https://github.com/microsoft/github-actions-for-desktop-apps
name: .NET Core Desktop
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
strategy:
matrix:
configuration: [Debug, Release]
runs-on: windows-latest # For a list of available runner types, refer to
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# NectarRcon Config
config.json
servers.json
passwords.json
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
================================================
FILE: LICENSE.txt
================================================
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: NectarRCON/App.xaml
================================================
<Application
x:Class="NectarRCON.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NectarRCON"
xmlns:sys="clr-namespace:System;assembly=netstandard"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Exit="OnExit"
Startup="OnStartup">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
<ResourceDictionary Source="pack://application:,,,/NectarRCON;component/Resources/Languages/zh_cn.xaml" />
<ResourceDictionary>
<sys:String x:Key="app.version">1.0.0-beta5</sys:String>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
================================================
FILE: NectarRCON/App.xaml.cs
================================================
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NectarRCON.Interfaces;
using NectarRCON.Rcon;
using NectarRCON.Services;
using NectarRCON.ViewModels;
using NectarRCON.Windows;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Extensions.Logging;
using NectarRCON.Dp;
using Serilog;
using Wpf.Ui.Mvvm.Contracts;
using Wpf.Ui.Mvvm.Services;
namespace NectarRCON;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
private static readonly ILoggerFactory LoggerFactory = new LoggerFactory();
private static string LogFileName = $"logs/program/log{DateTime.Now:yyyyMMddhhmm}.log";
private static readonly IHost Host = Microsoft.Extensions.Hosting.Host
.CreateDefaultBuilder()
.ConfigureLogging(builder =>
{
Log.Logger = new LoggerConfiguration()
.WriteTo.File(LogFileName,
rollingInterval: RollingInterval.Infinite, flushToDiskInterval: TimeSpan.FromSeconds(1))
.CreateLogger();
builder.AddSerilog();
})
.ConfigureServices((context, services) =>
{
services.AddSingleton(LoggerFactory);
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddHostedService<ApplicationHostService>();
services.AddSingleton<ILanguageService, LanguageService>();
services.AddSingleton<IConfigService, ConfigService>();
services.AddSingleton<ILogService, LogService>();
services.AddSingleton<IHistoryService, HistoryService>();
services.AddSingleton<IServerPasswordService, ServerPasswordService>();
services.AddSingleton<IThemeService, ThemeService>();
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<ISnackbarService, SnackbarService>();
services.AddSingleton<IServerInformationService, ServerInformationService>();
services.AddSingleton<IConnectingDialogService, ConnectingDialogService>();
// Rcon Connections
services.AddSingleton<IRconConnectionInfoService, RconConnectionInfoService>();
services.AddSingleton<IRconConnection, RconSingleConnection>();
services.AddSingleton<IRconConnection, RconMultiConnection>();
services.AddSingleton<IMessageBoxService, MessageBoxService>();
services.AddSingleton<IGroupService, GroupService>();
services.AddScoped<INavigationWindow, MainWindow>();
services.AddScoped<MainWindowViewModel>();
services.AddTransient<AddServerWindow>();
services.AddTransient<AddServerWindowViewModel>();
}).Build();
public static T GetService<T>()
where T : class
{
return (Host.Services.GetService(typeof(T)) as T)!;
}
public static T GetService<T>(Type type)
where T : class
{
return Host.Services.GetServices<T>().FirstOrDefault(t => t.GetType() == type)!;
}
private async void OnStartup(object sender, StartupEventArgs e)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
foreach (var rconEncoding in Enum.GetValues<Dp.RconEncoding>())
{
rconEncoding.GetEncoding();
}
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
await Host.StartAsync();
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception;
Log.Error("未经处理的异常: {0}", exception);
MessageBox.Show(
exception +
$"\n\n程序遇到异常,即将退出!\n建议前往Github提交Issue\n请前往日志查看详细信息!\nCheck log: {Path.Combine(Environment.CurrentDirectory, LogFileName).Replace("\\", "/")}",
"程序崩溃", MessageBoxButton.OK, MessageBoxImage.Error);
Environment.Exit(1);
}
private async void OnExit(object sender, ExitEventArgs e)
{
await Host.StopAsync();
Host.Dispose();
}
}
================================================
FILE: NectarRCON/AssemblyInfo.cs
================================================
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
================================================
FILE: NectarRCON/Converters/BoolToVisibilityConverter.cs
================================================
using System;
using System.Windows.Data;
using System.Windows;
using System.Globalization;
namespace NectarRCON.Converters
{
public class BoolToVisibilityConverter : IValueConverter
{
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is bool boolValue)
{
return boolValue ? Visibility.Visible : Visibility.Hidden;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
================================================
FILE: NectarRCON/Converters/IntToVisibilityConverter.cs
================================================
using System;
using System.Windows.Data;
using System.Windows;
using System.Globalization;
namespace NectarRCON.Converters
{
public class IntToVisibilityConverter : IValueConverter
{
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is int intValue)
{
if(parameter is string boolStringValue)
{
bool boolValue = System.Convert.ToBoolean(boolStringValue);
// 如果参数为False
// <= 0 ? Visible : Hidden
// 否则反过来
return boolValue
? (intValue <= 0 ? Visibility.Hidden : Visibility.Visible)
: (intValue <= 0 ? Visibility.Visible : Visibility.Hidden);
}
return intValue <= 0 ? Visibility.Visible : Visibility.Hidden;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
================================================
FILE: NectarRCON/Dp/DpFile.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace NectarRCON.Dp;
/// <summary>
/// 数据持久化文件
/// </summary>
public abstract class DpFile
{
/// <summary>
/// 文件名
/// </summary>
protected abstract string Name { get; }
/// <summary>
/// 文件路径
/// </summary>
protected virtual string BasePath => string.Empty;
/// <summary>
/// 实例映射
/// </summary>
private static readonly Dictionary<Type, DpFile> InstanceMapping = [];
/// <summary>
/// 保存数据
/// </summary>
public void Save()
{
var json = JsonSerializer.Serialize((object)this);
var filePath = Path.Combine(AppContext.BaseDirectory,"dp", BasePath, Name);
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
File.WriteAllText(filePath, json);
}
/// <summary>
/// 加载数据
/// </summary>
/// <param name="name">文件名</param>
/// <param name="basePath">文件路径</param>
/// <typeparam name="T">类型</typeparam>
/// <returns>实例</returns>
private static T? Load<T>(string name, string? basePath = null)
where T : DpFile
{
var filePath = Path.Combine(AppContext.BaseDirectory, "dp", basePath ?? string.Empty, name);
if (!File.Exists(filePath)) return null;
var json = File.ReadAllText(filePath);
return JsonSerializer.Deserialize<T>(json);
}
/// <summary>
/// 以单例模式加载数据
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <returns>实例</returns>
public static T LoadSingleton<T>()
where T:DpFile
{
// 先从_instanceMapping拿数据
if (InstanceMapping.TryGetValue(typeof(T), out var cachedInstance))
{
return (T)cachedInstance;
}
// 如果缓存没有 则使用找到此DPFile的无参构造函数 使用反射实例化后存放到_instanceMapping
var instance = Activator.CreateInstance<T>();
// 从instance中获取Name 随后load
InstanceMapping[typeof(T)] = Load<T>(instance.Name, instance.BasePath) ?? instance;
return (T)InstanceMapping[typeof(T)];
}
}
================================================
FILE: NectarRCON/Dp/RconSettingsDp.cs
================================================
using System.Text;
using System.Text.Json.Serialization;
namespace NectarRCON.Dp;
public enum RconEncoding
{
Utf8 = 0,
Utf16 = 1,
Utf32 = 2,
Gb2312 = 3,
Gbk = 4,
Gb18030 = 5,
Ascii = 6,
Big5 = 7,
HzGb2312 = 8,
}
public static class RconEncodingExtensions
{
public static Encoding GetEncoding(this RconEncoding encoding)
=> encoding switch
{
RconEncoding.Utf8 => Encoding.UTF8,
RconEncoding.Utf16 => Encoding.GetEncoding("UTF-16"),
RconEncoding.Utf32 => Encoding.UTF32,
RconEncoding.Gb2312 => Encoding.GetEncoding("gb2312"),
RconEncoding.Gbk => Encoding.GetEncoding("gbk"),
RconEncoding.Gb18030 => Encoding.GetEncoding("gb18030"),
RconEncoding.Ascii => Encoding.ASCII,
RconEncoding.Big5 => Encoding.GetEncoding("big5"),
RconEncoding.HzGb2312 => Encoding.GetEncoding("hz-gb-2312"),
_ => Encoding.UTF8,
};
}
public class RconSettingsDp : DpFile
{
protected override string Name => "rcon_settings.json";
/// <summary>
/// 连接时掉线自动尝试重连
/// </summary>
[JsonPropertyName("auto_reconnect")]
public bool AutoReconnect { get; set; } = true;
/// <summary>
/// 掉线后不关闭连接窗口
/// </summary>
/// <returns></returns>
[JsonPropertyName("is_keep_connection_window_open")]
public bool IsKeepConnectionWindowOpen { get; set; }
/// <summary>
/// 文本编码
/// </summary>
[JsonPropertyName("encoding")]
public RconEncoding Encoding { get; set; } = RconEncoding.Utf8;
}
================================================
FILE: NectarRCON/Entity/ClearLogValueMessage.cs
================================================
namespace NectarRCON.Models;
public partial class ClearLogValueMessage
{
}
================================================
FILE: NectarRCON/Entity/Config.cs
================================================
using System.Text.Json.Serialization;
namespace NectarRCON.Models;
public partial class Config
{
[JsonPropertyName("language")]
public string LanguageName { get; set; } = string.Empty;
[JsonPropertyName("theme")]
public ETheme Theme { get; set; }
[JsonPropertyName("command_list")]
public int CommandLimit;
}
================================================
FILE: NectarRCON/Entity/ETheme.cs
================================================
namespace NectarRCON.Models;
public enum ETheme : short
{
System = 0,
Dark = 1,
Light = 2
}
================================================
FILE: NectarRCON/Entity/Group.cs
================================================
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace NectarRCON.Models
{
public class Group
{
[JsonPropertyName("id")]
public required string Id { get; set; }
[JsonPropertyName("name")]
public required string Name { get; set; }
[JsonPropertyName("server_list")]
public required List<string> Servers { get; set; }
}
}
================================================
FILE: NectarRCON/Entity/MainPageLoadValueMessage.cs
================================================
namespace NectarRCON.Models;
public partial class MainPageLoadValueMessage
{
public required bool IsLoaded { get; init; }
}
================================================
FILE: NectarRCON/Entity/ServerInformation.cs
================================================
using System.Text.Json.Serialization;
namespace NectarRCON.Models;
public class ServerInformation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("address")]
public string Address { get; set; } = string.Empty;
[JsonPropertyName("adapter")]
public string Adapter { get; set; } = string.Empty; // 适配类名
[JsonPropertyName("port")]
public ushort Port { get; set; } = 0;
[JsonIgnore]
public string DisplayAddress
{
get => $"{Address}:{Port}";
}
}
================================================
FILE: NectarRCON/Entity/ServerPassword.cs
================================================
using System.Text.Json.Serialization;
namespace NectarRCON.Models;
public class ServerPassword
{
[JsonPropertyName("password")]
public string Password { get; set; } = string.Empty;
[JsonPropertyName("is_empty")]
public bool IsEmpty { get; set; }
[JsonPropertyName("name")]
public string ServerName { get; set; } = string.Empty;
}
================================================
FILE: NectarRCON/Interfaces/IConfigService.cs
================================================
using NectarRCON.Models;
namespace NectarRCON.Interfaces;
public interface IConfigService
{
void Save();
Config GetConfig();
}
================================================
FILE: NectarRCON/Interfaces/IConnectingDialogService.cs
================================================
using System.Windows.Controls;
namespace NectarRCON.Interfaces;
public interface IConnectingDialogService
{
void SetDialog(Grid grid);
void Show();
void Close();
}
================================================
FILE: NectarRCON/Interfaces/IGroupService.cs
================================================
using NectarRCON.Models;
using System.Collections.Generic;
namespace NectarRCON.Interfaces;
public interface IGroupService
{
/// <summary>
/// 获取所有组
/// </summary>
IReadOnlyList<Group> GetGroups();
/// <summary>
/// 通过组名字获取组
/// </summary>
/// <param name="name">组名</param>
Group? FindGroup(string name);
/// <summary>
/// 通过组Id获取组
/// </summary>
/// <param name="groupId">组Id</param>
Group? GetGroup(string groupId);
/// <summary>
/// 删除组
/// </summary>
/// <param name="groupId">组Id</param>
void Delete(string groupId);
/// <summary>
/// 添加一个组
/// </summary>
string Add(Group group);
}
================================================
FILE: NectarRCON/Interfaces/IHistoryService.cs
================================================
namespace NectarRCON.Interfaces;
public class HistoryNode
{
public string? Cmd { get; set; }
public HistoryNode? Prev { get; set; }
public HistoryNode? Next { get; set; }
}
public interface IHistoryService
{
/// <summary>
/// 获取前一条命令
/// </summary>
/// <param name="current"></param>
/// <returns></returns>
HistoryNode? Prev(HistoryNode? current);
/// <summary>
/// 获取后一条命令
/// </summary>
/// <param name="current"></param>
/// <returns></returns>
HistoryNode? Next(HistoryNode? current);
/// <summary>
/// 输入命令
/// </summary>
/// <param name="cmd"></param>
HistoryNode? InputCmd(string cmd);
}
================================================
FILE: NectarRCON/Interfaces/ILanguageService.cs
================================================
using System.Collections.Generic;
using System.Windows;
namespace NectarRCON.Interfaces;
public interface ILanguageService
{
public void Refresh();
public ResourceDictionary GetSelectedLanguage();
public Dictionary<string, ResourceDictionary> GetLanguages();
public void SelectLanguage();
public void SelectLanguage(string languageName, bool name);
public string GetKey(string key);
}
================================================
FILE: NectarRCON/Interfaces/ILogService.cs
================================================
using NectarRCON.Models;
namespace NectarRCON.Interfaces;
public interface ILogService
{
string GetText();
string Log(string message);
void Clear();
void SetServer(ServerInformation server);
void SetGroup(string groupId);
}
================================================
FILE: NectarRCON/Interfaces/IMessageBoxService.cs
================================================
using System;
using System.Windows;
namespace NectarRCON.Interfaces
{
public interface IMessageBoxService
{
void Show(string message);
void Show(string message, string title);
MessageBoxResult Show(string message, string title, MessageBoxButton button);
void Show(string message, string title, MessageBoxImage image);
MessageBoxResult Show(string message, string title, MessageBoxButton button, MessageBoxImage image);
void Show(Exception exception, string? information);
}
}
================================================
FILE: NectarRCON/Interfaces/IRconConnectionInfoService.cs
================================================
using NectarRCON.Models;
using System.Collections.Generic;
namespace NectarRCON.Interfaces;
public interface IRconConnectionInfoService
{
/// <summary>
/// 清除所有连接信息
/// </summary>
void Clear();
/// <summary>
/// 添加一个服务器
/// </summary>
void AddInformation(string serverName);
/// <summary>
/// 获取最后一个被添加的服务器
/// </summary>
ServerInformation? GetLastInformation();
/// <summary>
/// 获取所有的信息
/// </summary>
IReadOnlyList<ServerInformation> GetInformation();
/// <summary>
/// 是否拥有多个服务器信息
/// </summary>
public bool HasMultipleInformation
=> GetInformation().Count > 1;
}
================================================
FILE: NectarRCON/Interfaces/IServerInformationService.cs
================================================
using NectarRCON.Models;
using System.Collections.Generic;
namespace NectarRCON.Interfaces;
public interface IServerInformationService
{
ServerInformation? GetServer(string name);
List<ServerInformation> GetServers();
void AddServer(ServerInformation server);
void Save();
void RemoveServer(string name);
void Update(string name, ServerInformation newInfo);
bool ServerIsExist(string name);
}
================================================
FILE: NectarRCON/Interfaces/IServerPasswordService.cs
================================================
using NectarRCON.Models;
namespace NectarRCON.Interfaces;
public interface IServerPasswordService
{
void Save();
bool IsExist(ServerInformation server);
void Set(ServerInformation server, string? password, bool? isEmpty);
void Remove(ServerInformation server);
ServerPassword? Get(ServerInformation server);
ServerInformation GetSelect();
void Select(ServerInformation server);
}
================================================
FILE: NectarRCON/Models/GroupModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Rcon;
using NectarRCON.Services;
using NectarRCON.ViewModels;
using NectarRCON.Windows;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Linq;
using Wpf.Ui.Mvvm.Contracts;
namespace NectarRCON.Models;
public partial class GroupModel:ObservableObject
{
private readonly IGroupService _groupService;
private readonly ILanguageService _languageService;
private readonly IRconConnectionInfoService _connectionInfoService;
private IRconConnection _rconConnection;
private readonly INavigationService _navigationService;
private readonly IMessageBoxService _messageService;
private readonly IConnectingDialogService _connectingDialogService;
private readonly ILogService _logService;
[ObservableProperty]
private string _id;
[ObservableProperty]
private GroupPageViewModel _baseModel;
[ObservableProperty]
private string _name;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ConnectCommand))]
private ObservableCollection<GroupServerItemModel> _servers = new();
#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
public GroupModel(string name, GroupPageViewModel baseModel)
#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
{
_groupService = App.GetService<IGroupService>();
_languageService = App.GetService<ILanguageService>();
_connectionInfoService = App.GetService<IRconConnectionInfoService>();
_rconConnection = App.GetService<IRconConnection>(typeof(RconMultiConnection));
_navigationService = App.GetService<INavigationService>();
_messageService = App.GetService<IMessageBoxService>();
_connectingDialogService = App.GetService<IConnectingDialogService>();
_logService = App.GetService<ILogService>();
_baseModel = baseModel;
Name = name;
Id = _groupService.FindGroup(name)?.Id ?? throw new InvalidOperationException();
Refresh();
}
private void Refresh()
{
Group? group = _groupService.GetGroup(_id);
if (group != null)
{
Servers.Clear();
Name = group.Name;
foreach (var server in group.Servers)
{
Servers.Add(new(server, this));
}
}
}
[RelayCommand]
public void ItemRemove(string name)
{
Servers.Remove(Servers.Where(s => s.Name == name).First());
Save();
ConnectCommand.NotifyCanExecuteChanged();
}
private bool ConnectCommandCanExecute()
=> Servers.Count >= 1;
[RelayCommand(CanExecute = nameof(ConnectCommandCanExecute))]
public void Connect()
{
_logService.SetGroup(_id);
_connectionInfoService.Clear();
_connectingDialogService.Show();
foreach (var server in Servers)
{
_connectionInfoService.AddInformation(server.Name);
}
if (_connectionInfoService.HasMultipleInformation)
{
_rconConnection = App.GetService<IRconConnection>(typeof(RconMultiConnection));
}
else
{
_rconConnection = App.GetService<IRconConnection>(typeof(RconSingleConnection));
}
_navigationService.Navigate(0);
}
[RelayCommand]
public void Add()
{
JoinGroupWindow window = new();
foreach (var server in Servers)
{
window.AddBlackList(server.Name);
}
window.ShowDialog();
window.Close();
if (window.SelectedServer != null)
{
Servers.Add(new(window.SelectedServer, this));
Save();
}
ConnectCommand.NotifyCanExecuteChanged();
}
private void Save()
{
Group group = _groupService.GetGroup(_id)!;
group.Servers.Clear();
foreach (var server in Servers)
{
group.Servers.Add(server.Name);
}
_groupService.Delete(group.Id);
_groupService.Add(group);
Refresh();
}
}
================================================
FILE: NectarRCON/Models/GroupServerItemModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
namespace NectarRCON.Models;
public partial class GroupServerItemModel : ObservableObject
{
[ObservableProperty]
private string _name;
[ObservableProperty]
private GroupModel _baseModel;
#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
public GroupServerItemModel(string name, GroupModel baseModel)
#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
{
Name = name;
BaseModel = baseModel;
}
}
================================================
FILE: NectarRCON/Models/ServerModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Rcon;
using NectarRCON.Services;
using NectarRCON.ViewModels;
using NectarRCON.Windows;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Windows;
using Wpf.Ui.Mvvm.Contracts;
namespace NectarRCON.Models
{
public partial class ServerModel : ObservableObject
{
private readonly IServerPasswordService _passwordService;
private readonly IServerInformationService _informationService;
private readonly IConnectingDialogService _connectingDialogService;
private readonly IRconConnectionInfoService _connectionInfoService;
private readonly INavigationService _navigationService;
private readonly IServerPasswordService _serverPasswordService;
private readonly ILogService _logService;
private readonly ILanguageService _languageService;
private readonly ServerInformation _information;
private readonly ServersPageViewModel _viewModel;
private readonly IRconConnection _rconConnection;
[ObservableProperty]
private string _name;
[ObservableProperty]
private string _address;
#pragma warning disable CS8618 // CS8618 你说的对,但是我已经初始化了
public ServerModel(ServerInformation information, ServersPageViewModel viewModel)
#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
{
_passwordService = App.GetService<IServerPasswordService>();
_informationService = App.GetService<IServerInformationService>();
_languageService = App.GetService<ILanguageService>();
_connectingDialogService = App.GetService<IConnectingDialogService>();
_rconConnection = App.GetService<IRconConnection>(typeof(RconSingleConnection));
_connectionInfoService = App.GetService<IRconConnectionInfoService>();
_navigationService = App.GetService<INavigationService>();
_serverPasswordService = App.GetService<IServerPasswordService>();
_logService = App.GetService<ILogService>();
_information = information;
_viewModel = viewModel;
Name = information.Name;
Address = $"{information.Address}:{information.Port}";
}
private void EditPass()
{
_passwordService.Select(_information);
EditPasswordWindow window = new EditPasswordWindow();
window.ShowDialog();
}
[RelayCommand]
public void EditPassword()
{
EditPass();
}
[RelayCommand]
public void Edit()
{
_passwordService.Select(_information);
EditServerWindow window = new EditServerWindow();
window.ShowDialog();
_viewModel.Refresh();
}
[RelayCommand]
public void Delete()
{
var result = MessageBox.Show(_languageService.GetKey("ui.server_page.confirm"), _languageService.GetKey("ui.server_page.menu.delete"), MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
_informationService.RemoveServer(Name);
_informationService.Save();
_passwordService.Remove(_information);
_passwordService.Save();
_viewModel.Refresh();
}
}
[RelayCommand]
public void Connect()
{
_logService.SetServer(_information);
if (_rconConnection.IsConnecting())
return;
if (_rconConnection.IsConnected())
{
_rconConnection.Close();
}
var server = _passwordService.Get(_information);
if (server == null)
{
EditPass();
}
else if (server.Password == null && !server.IsEmpty)
{
EditPass();
}
_connectionInfoService.Clear();
_connectionInfoService.AddInformation(Name);
_serverPasswordService.Select(_information);
_navigationService.Navigate(0);
}
}
}
================================================
FILE: NectarRCON/NectarRCON.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<ApplicationIcon>Resources\Icon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Version>1.0.0-beta5</Version>
<LangVersion>12</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\head.png" />
<None Remove="Resources\Icon.png" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\Icon.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="Serilog" Version="3.1.2-dev-02097" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.1-dev-10370" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00972" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageReference Include="WPF-UI" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NectarRCON.Core\NectarRCON.Core.csproj" />
<ProjectReference Include="..\NectarRCON.Export\NectarRCON.Export.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\head.png" />
<Resource Include="Resources\Icon.png" />
</ItemGroup>
<ItemGroup>
<Page Update="Resources\Languages\en_us.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
</ItemGroup>
</Project>
================================================
FILE: NectarRCON/Rcon/IRconConnection.cs
================================================
using NectarRCON.Models;
namespace NectarRCON.Rcon;
public delegate void MessageEvent(ServerInformation information, string message);
public delegate void RconEvent(ServerInformation information);
public interface IRconConnection
{
event MessageEvent OnMessage;
event RconEvent OnClosed;
event RconEvent OnConnected;
event RconEvent OnConnecting;
void Connect();
void Send(string command);
void Close();
bool IsConnected();
bool IsConnecting();
}
================================================
FILE: NectarRCON/Rcon/RconMultiConnection.cs
================================================
using NectarRCON.Core.Helper;
using NectarRCON.Export.Interfaces;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using NectarRCON.Rcon;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Windows.Controls;
using NectarRCON.Dp;
using Serilog;
namespace NectarRCON.Services
{
/// <summary>
/// Rcon多客户端连接服务
/// </summary>
internal class RconMultiConnection(
IServerPasswordService serverPasswordService,
ILanguageService languageService,
IRconConnectionInfoService rconConnectionInfoService,
IMessageBoxService messageBoxService)
: IRconConnection, IDisposable
{
private readonly RconSettingsDp _settingsDp = DpFile.LoadSingleton<RconSettingsDp>();
public event MessageEvent? OnMessage;
public event RconEvent? OnClosed;
public event RconEvent? OnConnected;
public event RconEvent? OnConnecting;
private readonly Dictionary<ServerInformation,IRconAdapter> _connections = new();
private bool _isConnecting;
public void Close()
{
foreach(var connection in _connections)
{
connection.Value.Dispose();
}
_connections.Clear();
}
public void Connect()
{
Close();
_isConnecting = true;
var servers = rconConnectionInfoService.GetInformation();
try
{
foreach (ServerInformation info in servers)
{
OnConnecting?.Invoke(info);
// 准备开始连接,先解析这个地址有没有SRV记录
string address = DNSHelpers.SRVQuery(info.Address);
if (string.IsNullOrEmpty(address)) // 如果没有SRV记录,就按照原来的样子设置服务器
address = $"{info.Address.Replace("localhost", "127.0.0.1")}:{info.Port}";
ServerPassword? serverPassword = serverPasswordService.Get(info); // 从设置中读取Rcon密码
string password = serverPassword?.Password ?? string.Empty;
// 创建对应的Rcon客户端实例
// 目前支支持了Minecraft,后期会支持更多(嘛..主要是懒)
IRconAdapter adapter = AdapterHelpers.CreateAdapterInstance(info.Adapter)
?? throw new InvalidOperationException($"adapter not found: {info.Adapter}");
var host = address.Split(":")[0];
var port = int.Parse(address.Split(":")[1]);
Log.Information("[RconMultiConnection] Connecting to {host}:{port}", host, port);
try
{
adapter.Connect(host, port);
if (!adapter.Authenticate(password))
throw new AuthenticationException($"Server: \"{info.Name}\"\n");
OnConnected?.Invoke(info);
}
catch (AuthenticationException)
{
throw;
}
catch (Exception ex)
{
OnClosed?.Invoke(info);
messageBoxService.Show(ex, $"Server: \"{info.Name}\"");
}
//设置编码
adapter.SetEncoding(_settingsDp.Encoding.GetEncoding());
_connections.Add(info, adapter);
}
}
finally
{
_isConnecting = false;
}
}
public bool IsConnected()
=> _connections.Any(e => e.Value.IsConnected);
public bool IsConnecting()
=> _isConnecting;
public void Send(string command)
{
foreach(var value in _connections)
{
IRconAdapter connection = value.Value;
ServerInformation info = value.Key;
if (connection.IsConnected)
{
try
{
string result = connection.Run(command);
OnMessage?.Invoke(info, result);
}catch (IOException)
{
connection.Dispose(); // 内部会调用Close
OnClosed?.Invoke(info);
OnMessage?.Invoke(info, languageService.GetKey("service.rcon.offline"));
}
}
else
{
OnMessage?.Invoke(info, languageService.GetKey("service.rcon.offline"));
}
}
}
public void Dispose()
{
Close();
}
}
}
================================================
FILE: NectarRCON/Rcon/RconSingleConnection.cs
================================================
using NectarRCON.Core.Helper;
using NectarRCON.Export.Interfaces;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using NectarRCON.Rcon;
using System;
using System.IO;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Windows;
using NectarRCON.Dp;
using Serilog;
namespace NectarRCON.Services;
public class RconSingleConnection(
IServerPasswordService serverPasswordService,
ILanguageService languageService,
IRconConnectionInfoService rconConnectionInfoService)
: IRconConnection
{
private readonly RconSettingsDp _settingsDp = DpFile.LoadSingleton<RconSettingsDp>();
private IRconAdapter? _rconClient
= null;
private bool _connecting;
public event MessageEvent? OnMessage;
public event RconEvent? OnClosed;
public event RconEvent? OnConnected;
public event RconEvent? OnConnecting;
private ServerInformation _serverInformation = new();
public void Close()
{
lock (this)
{
if (IsConnected() && !IsConnecting())
{
_connecting = false;
_rconClient?.Dispose();
_rconClient = null;
OnClosed?.Invoke(_serverInformation);
}
}
}
public void Connect()
{
ServerInformation info = rconConnectionInfoService.GetLastInformation() ?? throw new ArgumentNullException("Internal error, please try again");
_connecting = true;
OnConnecting?.Invoke(info);
try
{
if (IsConnected() && _rconClient != null)
Close();
// 准备开始连接,先解析这个地址有没有SRV记录
string address = DNSHelpers.SRVQuery(info.Address);
if (string.IsNullOrEmpty(address)) // 如果没有SRV记录,就按照原来的样子设置服务器
address = $"{info.Address.Replace("localhost", "127.0.0.1")}:{info.Port}";
ServerPassword? serverPassword = serverPasswordService.Get(info);
string password = serverPassword?.Password ?? string.Empty;
// 创建对应的Rcon客户端实例
// 目前支支持了Minecraft,后期会支持更多(嘛..主要是懒)
_rconClient = AdapterHelpers.CreateAdapterInstance(info.Adapter)
?? throw new InvalidOperationException($"adapter not found: {info.Adapter}");
_rconClient.SetEncoding(_settingsDp.Encoding.GetEncoding());
var host = address.Split(":")[0];
var port = int.Parse(address.Split(":")[1]);
Log.Information("[RconSingleConnection] Connecting to {host}:{port}", host, port);
_rconClient.Connect(host, port); // 连接
if (!_rconClient.Authenticate(password))
throw new AuthenticationException();
OnConnected?.Invoke(info);
_serverInformation = info;
}
catch (FormatException ex)
{
MessageBox.Show(languageService.GetKey("ui.text.format_exception")
.Replace("%s", ex.Message), languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
_connecting = false;
}
}
public bool IsConnected()
=> _rconClient?.IsConnected ?? false;
public bool IsConnecting()
=> _connecting;
public void Send(string command)
{
if (IsConnected() && _rconClient != null)
{
try
{
string result = _rconClient.Run(command);
OnMessage?.Invoke(_serverInformation, result);
}
catch (Exception ex)
{
Close();
if (ex is SocketException or IOException && _settingsDp.AutoReconnect)
{
Log.Information("Rcon连接已经断开,开始自动重连...");
try
{
Connect();
}
catch (Exception e)
{
Log.Error("自动重连失败 {err}", e);
}
if (IsConnected())
{
try
{
Log.Information("尝试重发命令...");
string result = _rconClient.Run(command);
OnMessage?.Invoke(_serverInformation, result);
Log.Information("重发命令成功 -> {command}", command);
return;
}
catch(Exception e)
{
Log.Error("尝试重发命令失败 {err}", e);
}
}
}
MessageBox.Show($"{languageService.GetKey("text.error")}\n{ex.Message}", ex.GetType().FullName, MessageBoxButton.OK, MessageBoxImage.Error);
}
}
else
{
Close();
MessageBox.Show($"{languageService.GetKey("text.server.not_connect.text")}", languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
================================================
FILE: NectarRCON/Resources/Languages/en_us.xaml
================================================
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<sys:String x:Key="file.language">en_us</sys:String>
<sys:String x:Key="file.name">English US(en_us)</sys:String>
<sys:String x:Key="ui.menu.server">Server</sys:String>
<sys:String x:Key="ui.menu.server_list">Servers</sys:String>
<sys:String x:Key="ui.menu.groups">Groups</sys:String>
<sys:String x:Key="ui.menu.log">Log</sys:String>
<sys:String x:Key="ui.menu.log.clear">Clear</sys:String>
<sys:String x:Key="ui.menu.program">Program</sys:String>
<sys:String x:Key="ui.menu.program.settings">Settings</sys:String>
<sys:String x:Key="ui.menu.program.about">About</sys:String>
<sys:String x:Key="ui.menu.program.check_update">CheckUpdate</sys:String>
<sys:String x:Key="ui.window.title">RCONManager</sys:String>
<sys:String x:Key="ui.settings.language">UI Language</sys:String>
<sys:String x:Key="ui.settings.ui">UI Settings</sys:String>
<sys:String x:Key="ui.settings.theme">UI Theme</sys:String>
<sys:String x:Key="ui.settings.theme.dark">Dark Theme</sys:String>
<sys:String x:Key="ui.settings.theme.light">Light Theme</sys:String>
<sys:String x:Key="ui.settings.theme.auto">System Theme</sys:String>
<sys:String x:Key="ui.settings.rcon_account">Rcon passwords...</sys:String>
<sys:String x:Key="ui.settings.command_record_limit">Command Record Limit</sys:String>
<sys:String x:Key="ui.settings.rcon">Rcon</sys:String>
<sys:String x:Key="ui.settings.rcon.auto_reconnect">Auto Reconnect</sys:String>
<sys:String x:Key="ui.settings.rcon.is_keep_connection_window_open">KeepConnectionWindowOpen</sys:String>
<sys:String x:Key="ui.settings.rcon.encoding">Encoding</sys:String>
<sys:String x:Key="ui.menu.log.clear_program">Clear Program Logs</sys:String>
<sys:String x:Key="ui.menu.log.clear_program.ask">Do you want to clear program logs?</sys:String>
<sys:String x:Key="ui.server_page.menu.open">Connect</sys:String>
<sys:String x:Key="ui.server_page.menu.edit">Edit</sys:String>
<sys:String x:Key="ui.server_page.menu.delete">Delete</sys:String>
<sys:String x:Key="ui.server_page.menu.edit_password">EditPassword</sys:String>
<sys:String x:Key="ui.server_page.text">Servers</sys:String>
<sys:String x:Key="ui.server_page.add">Add Server</sys:String>
<sys:String x:Key="ui.server_page.search">Search by server name...</sys:String>
<sys:String x:Key="ui.server_page.confirm">This action will delete the server! (including recorded password)\nAre you sure you want to delete?</sys:String>
<sys:String x:Key="ui.add_server_window.title">Add Server</sys:String>
<sys:String x:Key="ui.add_server_window.name">Name</sys:String>
<sys:String x:Key="ui.add_server_window.address">Address</sys:String>
<sys:String x:Key="ui.add_server_window.port">Port</sys:String>
<sys:String x:Key="ui.add_server_window.add">Add</sys:String>
<sys:String x:Key="ui.add_server_window.cancel">Cancel</sys:String>
<sys:String x:Key="ui.add_server_window.already_exist">A server with the same name already exists, please change your name!</sys:String>
<sys:String x:Key="ui.add_server_window.null_text">Server name or server address cannot be empty, please change it!</sys:String>
<sys:String x:Key="ui.about.afdian">Afdian</sys:String>
<sys:String x:Key="ui.about.mcbbs">MCBBS</sys:String>
<sys:String x:Key="ui.about.github">Github</sys:String>
<sys:String x:Key="ui.text.format_exception">An error was encountered while parsing the destination address: %s\nPlease check whether the server address is legal!</sys:String>
<sys:String x:Key="ui.edit_password.title">Edit Password</sys:String>
<sys:String x:Key="ui.edit_password.text">Password</sys:String>
<sys:String x:Key="ui.edit_password.is_empty">Empty Pass</sys:String>
<sys:String x:Key="ui.main_page.run">Run</sys:String>
<sys:String x:Key="ui.main_page.successful">Successful!</sys:String>
<sys:String x:Key="ui.main_page.offline.single">Offline</sys:String>
<sys:String x:Key="ui.main_page.offline.multiple">All clients are offline</sys:String>
<sys:String x:Key="ui.main_page.re_connect">Reconnect</sys:String>
<sys:String x:Key="ui.main_page.back_home">Back to Servers</sys:String>
<sys:String x:Key="ui.edit_server_window.title">Edit</sys:String>
<sys:String x:Key="text.went_wrong">An exception occurred during operation, and the application is about to end. If you cannot understand the error below, please submit an issue on Github and describe what happened in detail</sys:String>
<sys:String x:Key="text.error">Error</sys:String>
<sys:String x:Key="text.warn">Warning</sys:String>
<sys:String x:Key="text.info">Information</sys:String>
<sys:String x:Key="text.ok">Ok</sys:String>
<sys:String x:Key="text.cancel">Cancel</sys:String>
<sys:String x:Key="text.not_available">Not Available</sys:String>
<sys:String x:Key="text.connect">Connect</sys:String>
<sys:String x:Key="text.remove">Remove</sys:String>
<sys:String x:Key="text.delete">Delete</sys:String>
<sys:String x:Key="text.add">Add</sys:String>
<sys:String x:Key="text.server.connect.ing">Connecting...</sys:String>
<sys:String x:Key="text.server.connect.fail">Failed to connect to the server!</sys:String>
<sys:String x:Key="text.server.connect.fail.text">Unable to connect to the remote server: %s\nPlease check that the server RCON address is configured correctly, and check that the server has enabled the RCON option!</sys:String>
<sys:String x:Key="text.server.connect.auth_fail">The Rcon password is incorrect, please check whether your server password is correct!</sys:String>
<sys:String x:Key="text.server.connected">Connected to the server and authenticated successfully!</sys:String>
<sys:String x:Key="text.server.closed">The connection is disconnected!</sys:String>
<sys:String x:Key="text.server.start">Starting connection</sys:String>
<sys:String x:Key="text.server.not_connect.text">You cannot connect to the server, so you cannot use the remote command function, please try to go back to the server list and reconnect to this server!</sys:String>
<sys:String x:Key="text.server_information.error.json_error">Unable to instantiate server list /servers.json %s\nClick "Yes" to reset the server list (you need to re-add the server, but the recorded password will not disappear)\nClick "Cancel" to close the program!</sys:String>
<sys:String x:Key="text.server_information.error.text">Unable to instantiate server list /servers.json %s\nClick "Yes" to close the program!</sys:String>
<sys:String x:Key="text.server_information.error.save">Unable to save file /servers.json\nIf you just added a server, please note that this save is not in effect!\n%s</sys:String>
<sys:String x:Key="text.password.error.json_error">Unable to resolve password list /passwords.json %s\nClick "Yes" to reset the password list (password needs to be reset, but the recorded server will not disappear)\nClick "Cancel" to close the program!</sys:String>
<sys:String x:Key="text.password.error.text">Unable to resolve password list /passwords.json %s\nClick "Yes" to close the program!</sys:String>
<sys:String x:Key="text.password.error.save">Unable to save file /passwords.json\nIf you have just set a password, please note that this save is not in effect!\n%s</sys:String>
<sys:String x:Key="text.config.json_error">Unable to resolve configuration file /config.json JSON parsing failed: %s\nClick "Yes" to reset the profile!\nClick "No" to exit the program!</sys:String>
<sys:String x:Key="text.config.error">Unable to parse configuration file /config.json: %s\nClick "Yes" to reset the profile!\nClick "No" to exit the program!</sys:String>
<sys:String x:Key="text.config.save_error">Unable to save configuration file /config.json: %s\nIf you have just changed the configuration file, please note that the save does not take effect!</sys:String>
<sys:String x:Key="groups.exception.invalid_data_exception">An error occurred while trying to read and parse the group file "{0}", trying to delete or repair the file may resolve this error!</sys:String>
<sys:String x:Key="groups.exception.same_group_id_exception">The same GroupId already exists (existing value: {0}, duplicate value: {1})</sys:String>
<sys:String x:Key="groups.exception.same_name_exception">The same Name already exists (existing id: {0}, duplicate id: {1})</sys:String>
<sys:String x:Key="groups.exception.group_id_exists_exception">A group with the same internal ID already exists in the file, try creating it again</sys:String>
<sys:String x:Key="groups.exception.file_name_mismatch_exception">The {0} file name does not match the internal ID {1}</sys:String>
<sys:String x:Key="groups.exception.name_already_exists_exception">The same Name already exists</sys:String>
<sys:String x:Key="ui.group.no_group_title">Click '+ Add' to add a group!</sys:String>
<sys:String x:Key="ui.group.no_group_subtitle">After adding a group, you can broadcast a command to all servers in that group simultaneously.</sys:String>
<sys:String x:Key="ui.group.no_server">This group has no servers. Click '+ Add' to add a server.</sys:String>
<sys:String x:Key="ui.group.delete_group">Do you want to delete group {0}?</sys:String>
<sys:String x:Key="ui.add_group.title">New Group</sys:String>
<sys:String x:Key="ui.add_group.placeholder_text">Group Name</sys:String>
<sys:String x:Key="ui.join_group.title">Select Server</sys:String>
<sys:String x:Key="ui.join_group.no_server">No server available</sys:String>
<sys:String x:Key="service.rcon.offline">Offline</sys:String>
</ResourceDictionary>
================================================
FILE: NectarRCON/Resources/Languages/zh_cn.xaml
================================================
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<sys:String x:Key="file.language">zh_cn</sys:String>
<sys:String x:Key="file.name">简体中文(zh_cn)</sys:String>
<sys:String x:Key="ui.menu.server">服务器</sys:String>
<sys:String x:Key="ui.menu.server_list">服务器列表</sys:String>
<sys:String x:Key="ui.menu.groups">服务器分组</sys:String>
<sys:String x:Key="ui.menu.log">日志</sys:String>
<sys:String x:Key="ui.menu.log.clear">清空日志</sys:String>
<sys:String x:Key="ui.menu.program">程序</sys:String>
<sys:String x:Key="ui.menu.program.settings">设置</sys:String>
<sys:String x:Key="ui.menu.program.about">关于</sys:String>
<sys:String x:Key="ui.menu.program.check_update">检查更新</sys:String>
<sys:String x:Key="ui.window.title">RCON管理器</sys:String>
<sys:String x:Key="ui.settings.language">UI语言</sys:String>
<sys:String x:Key="ui.settings.ui">界面设置</sys:String>
<sys:String x:Key="ui.settings.theme">UI主题</sys:String>
<sys:String x:Key="ui.settings.theme.dark">深色主题</sys:String>
<sys:String x:Key="ui.settings.theme.light">浅色主题</sys:String>
<sys:String x:Key="ui.settings.theme.auto">跟随系统</sys:String>
<sys:String x:Key="ui.settings.rcon_account">Rcon密码管理</sys:String>
<sys:String x:Key="ui.settings.command_record_limit">服务器命令回溯记录数</sys:String>
<sys:String x:Key="ui.settings.rcon">Rcon全局设置</sys:String>
<sys:String x:Key="ui.settings.rcon.auto_reconnect">掉线自动重连</sys:String>
<sys:String x:Key="ui.settings.rcon.is_keep_connection_window_open">掉线不回到主页</sys:String>
<sys:String x:Key="ui.settings.rcon.encoding">文本编码</sys:String>
<sys:String x:Key="ui.menu.log.clear_program">清理程序日志</sys:String>
<sys:String x:Key="ui.menu.log.clear_program.ask">是否清理程序日志?</sys:String>
<sys:String x:Key="ui.server_page.menu.open">连接</sys:String>
<sys:String x:Key="ui.server_page.menu.edit">编辑</sys:String>
<sys:String x:Key="ui.server_page.menu.delete">删除</sys:String>
<sys:String x:Key="ui.server_page.menu.edit_password">密码</sys:String>
<sys:String x:Key="ui.server_page.text">服务器列表</sys:String>
<sys:String x:Key="ui.server_page.add">添加服务器</sys:String>
<sys:String x:Key="ui.server_page.search">输入服务器名字来搜索...</sys:String>
<sys:String x:Key="ui.server_page.confirm">此操作将会删除服务器! (包括记录的密码)\n您确定要删除吗?</sys:String>
<sys:String x:Key="ui.add_server_window.title">添加服务器</sys:String>
<sys:String x:Key="ui.add_server_window.name">服务器名称</sys:String>
<sys:String x:Key="ui.add_server_window.address">服务器地址</sys:String>
<sys:String x:Key="ui.add_server_window.port">服务器端口</sys:String>
<sys:String x:Key="ui.add_server_window.add">新建</sys:String>
<sys:String x:Key="ui.add_server_window.cancel">取消</sys:String>
<sys:String x:Key="ui.add_server_window.already_exist">相同名字的服务器已存在,请换一个名字!</sys:String>
<sys:String x:Key="ui.add_server_window.null_text">服务器名称或服务器地址不可为空,请更改!</sys:String>
<sys:String x:Key="ui.about.afdian">爱发电</sys:String>
<sys:String x:Key="ui.about.mcbbs">MCBBS</sys:String>
<sys:String x:Key="ui.about.github">Github</sys:String>
<sys:String x:Key="ui.text.format_exception">解析目标地址时遇到错误: %s\n请检查服务器地址是否合法!</sys:String>
<sys:String x:Key="ui.edit_password.title">编辑密码</sys:String>
<sys:String x:Key="ui.edit_password.text">密码</sys:String>
<sys:String x:Key="ui.edit_password.is_empty">无需密码</sys:String>
<sys:String x:Key="ui.main_page.run">执行</sys:String>
<sys:String x:Key="ui.main_page.successful">执行成功</sys:String>
<sys:String x:Key="ui.main_page.offline.single">已掉线</sys:String>
<sys:String x:Key="ui.main_page.offline.multiple">所有客户端都掉线了</sys:String>
<sys:String x:Key="ui.main_page.re_connect">重新连接</sys:String>
<sys:String x:Key="ui.main_page.back_home">回到主页</sys:String>
<sys:String x:Key="ui.edit_server_window.title">编辑</sys:String>
<sys:String x:Key="text.went_wrong">运行过程中出现异常,应用即将结束。 如果您无法理解以下错误,请在 Github 上提交问题并详细描述发生的情况</sys:String>
<sys:String x:Key="text.error">错误</sys:String>
<sys:String x:Key="text.warn">警告</sys:String>
<sys:String x:Key="text.info">信息</sys:String>
<sys:String x:Key="text.ok">确定</sys:String>
<sys:String x:Key="text.cancel">取消</sys:String>
<sys:String x:Key="text.not_available">不可使用</sys:String>
<sys:String x:Key="text.connect">连接</sys:String>
<sys:String x:Key="text.remove">移除</sys:String>
<sys:String x:Key="text.delete">删除</sys:String>
<sys:String x:Key="text.add">添加</sys:String>
<sys:String x:Key="text.server.connect.ing">正在连接服务器...</sys:String>
<sys:String x:Key="text.server.connect.fail">连接服务器失败!</sys:String>
<sys:String x:Key="text.server.connect.fail.text">无法连接到远程服务器: %s\n请检查服务器RCON地址配置是否正确,以及检查服务端是否开启了RCON选项!</sys:String>
<sys:String x:Key="text.server.connect.auth_fail">Rcon密码错误,请检查您的服务器密码是否正确!</sys:String>
<sys:String x:Key="text.server.connected">连接服务器并认证成功!</sys:String>
<sys:String x:Key="text.server.closed">连接已断开!</sys:String>
<sys:String x:Key="text.server.start">开始连接</sys:String>
<sys:String x:Key="text.server.not_connect.text">无法连接到服务器,因此无法使用远程命令功能,请尝试回到服务器列表重新连接到本服务器!</sys:String>
<sys:String x:Key="text.server_information.error.json_error">无法解析服务器列表 /servers.json %s\n点击"是"重置服务器列表(需重新添加服务器,但记录的密码不会消失)\n点击"取消"关闭程序!</sys:String>
<sys:String x:Key="text.server_information.error.text">无法解析服务器列表 /servers.json %s\n点击"是"关闭程序!</sys:String>
<sys:String x:Key="text.server_information.error.save">无法保存文件 /servers.json\n如果您刚刚进行了添加服务器操作,请注意,本次保存并未生效!\n%s</sys:String>
<sys:String x:Key="text.password.error.json_error">无法解析密码列表 /passwords.json %s\n点击"是"重置密码列表(需重新设置密码,但记录的服务器不会消失)\n点击"取消"关闭程序!</sys:String>
<sys:String x:Key="text.password.error.text">无法解析密码列表 /passwords.json %s\n点击"是"关闭程序!</sys:String>
<sys:String x:Key="text.password.error.save">无法保存文件 /passwords.json\n如果您刚刚进行了设置密码操作,请注意,本次保存并未生效!\n%s</sys:String>
<sys:String x:Key="text.config.json_error">无法解析配置文件 /config.json JSON解析失败: %s\n点击"是"重置配置文件!\n点击"否"退出程序!</sys:String>
<sys:String x:Key="text.config.error">无法解析配置文件 /config.json: %s\n点击"是"重置配置文件!\n点击"否"退出程序!</sys:String>
<sys:String x:Key="text.config.save_error">无法保存配置文件 /config.json: %s\n如果您刚刚更改了配置文件,请注意,保存并未生效!</sys:String>
<sys:String x:Key="groups.exception.invalid_data_exception">读取和解析组文件"{0}"时发生错误,请尝试删除或修复文件以解决此错误!</sys:String>
<sys:String x:Key="groups.exception.same_group_id_exception">相同的 GroupId 已存在(现有值: {0},重复值: {1})</sys:String>
<sys:String x:Key="groups.exception.same_name_exception">相同的 Name 已存在(现有Id: {0},重复Id: {1})</sys:String>
<sys:String x:Key="groups.exception.group_id_exists_exception">文件中已存在具有相同内部 ID 的分组,请再次尝试创建</sys:String>
<sys:String x:Key="groups.exception.file_name_mismatch_exception">{0} 文件名与内部 ID {1} 不匹配</sys:String>
<sys:String x:Key="groups.exception.name_already_exists_exception">相同的组名已存在</sys:String>
<sys:String x:Key="ui.group.no_group_title">单击'+ 添加'添加一个组吧!</sys:String>
<sys:String x:Key="ui.group.no_group_subtitle">添加组后,可以将命令同时广播到该组的所有服务器</sys:String>
<sys:String x:Key="ui.group.no_server">该组没有任何服务器,请单击 '+ 添加' 添加一个服务器吧!</sys:String>
<sys:String x:Key="ui.group.delete_group">是否要删除组 {0}?</sys:String>
<sys:String x:Key="ui.add_group.title">新建组</sys:String>
<sys:String x:Key="ui.add_group.placeholder_text">组名</sys:String>
<sys:String x:Key="ui.join_group.title">选择服务器</sys:String>
<sys:String x:Key="ui.join_group.no_server">没有可用服务器</sys:String>
<sys:String x:Key="service.rcon.offline">离线</sys:String>
</ResourceDictionary>
================================================
FILE: NectarRCON/Resources/Languages/zh_tw.xaml
================================================
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<sys:String x:Key="file.language">zh_tw</sys:String>
<sys:String x:Key="file.name">繁体中文(zh_tw)</sys:String>
<sys:String x:Key="ui.menu.server">伺服器</sys:String>
<sys:String x:Key="ui.menu.server_list">伺服器列表</sys:String>
<sys:String x:Key="ui.menu.groups">伺服器分組</sys:String>
<sys:String x:Key="ui.menu.log">日誌</sys:String>
<sys:String x:Key="ui.menu.log.clear">清空日誌</sys:String>
<sys:String x:Key="ui.menu.program">程式</sys:String>
<sys:String x:Key="ui.menu.program.settings">設定</sys:String>
<sys:String x:Key="ui.menu.program.about">關於</sys:String>
<sys:String x:Key="ui.menu.program.check_update">檢查更新</sys:String>
<sys:String x:Key="ui.window.title">RCON管理器</sys:String>
<sys:String x:Key="ui.settings.language">UI語言</sys:String>
<sys:String x:Key="ui.settings.ui">界面設定</sys:String>
<sys:String x:Key="ui.settings.theme">UI主題</sys:String>
<sys:String x:Key="ui.settings.theme.dark">深色主題</sys:String>
<sys:String x:Key="ui.settings.theme.light">淺色主題</sys:String>
<sys:String x:Key="ui.settings.theme.auto">跟隨系統</sys:String>
<sys:String x:Key="ui.settings.rcon_account">Rcon密碼管理</sys:String>
<sys:String x:Key="ui.settings.command_record_limit">伺服器命令回溯記錄數</sys:String>
<sys:String x:Key="ui.settings.rcon">Rcon全局設定</sys:String>
<sys:String x:Key="ui.settings.rcon.auto_reconnect">斷綫自動重連</sys:String>
<sys:String x:Key="ui.settings.rcon.is_keep_connection_window_open">斷線不回到主頁</sys:String>
<sys:String x:Key="ui.settings.rcon.encoding">文本編碼</sys:String>
<sys:String x:Key="ui.menu.log.clear_program">清除程式日誌</sys:String>
<sys:String x:Key="ui.menu.log.clear_program.ask">您是否要清除程式日誌?</sys:String>
<sys:String x:Key="ui.server_page.menu.open">連線</sys:String>
<sys:String x:Key="ui.server_page.menu.edit">編輯</sys:String>
<sys:String x:Key="ui.server_page.menu.delete">刪除</sys:String>
<sys:String x:Key="ui.server_page.menu.edit_password">密碼</sys:String>
<sys:String x:Key="ui.server_page.text">伺服器列表</sys:String>
<sys:String x:Key="ui.server_page.add">新增伺服器</sys:String>
<sys:String x:Key="ui.server_page.search">輸入伺服器名稱來搜尋...</sys:String>
<sys:String x:Key="ui.server_page.confirm">此操作將會刪除伺服器! (包括記錄的密碼)\n您確定要刪除嗎?</sys:String>
<sys:String x:Key="ui.add_server_window.title">新增伺服器</sys:String>
<sys:String x:Key="ui.add_server_window.name">伺服器名稱</sys:String>
<sys:String x:Key="ui.add_server_window.address">伺服器地址</sys:String>
<sys:String x:Key="ui.add_server_window.port">伺服器端口</sys:String>
<sys:String x:Key="ui.add_server_window.add">新增</sys:String>
<sys:String x:Key="ui.add_server_window.cancel">取消</sys:String>
<sys:String x:Key="ui.add_server_window.already_exist">相同名稱的伺服器已經存在,請換一個名稱!</sys:String>
<sys:String x:Key="ui.add_server_window.null_text">伺服器名稱或伺服器地址不可為空,請更改!</sys:String>
<sys:String x:Key="ui.about.afdian">爱发电</sys:String>
<sys:String x:Key="ui.about.mcbbs">MCBBS</sys:String>
<sys:String x:Key="ui.about.github">Github</sys:String>
<sys:String x:Key="ui.text.format_exception">解析目标地址時遇到錯誤:%s\n請檢查伺服器地址是否合法!</sys:String>
<sys:String x:Key="ui.edit_password.title">編輯密碼</sys:String>
<sys:String x:Key="ui.edit_password.text">密碼</sys:String>
<sys:String x:Key="ui.edit_password.is_empty">無需密碼</sys:String>
<sys:String x:Key="ui.main_page.run">執行</sys:String>
<sys:String x:Key="ui.main_page.successful">執行成功</sys:String>
<sys:String x:Key="ui.main_page.offline.single">斷線</sys:String>
<sys:String x:Key="ui.main_page.offline.multiple">所有客戶端都斷線了</sys:String>
<sys:String x:Key="ui.main_page.re_connect">重新連接</sys:String>
<sys:String x:Key="ui.main_page.back_home">返回伺服器</sys:String>
<sys:String x:Key="ui.edit_server_window.title">編輯</sys:String>
<sys:String x:Key="text.went_wrong">執行過程中出現異常,應用即將結束。如果您無法理解以下錯誤,請在 GitHub 上提交問題並詳細描述發生的情況。</sys:String>
<sys:String x:Key="text.error">錯誤</sys:String>
<sys:String x:Key="text.warn">警告</sys:String>
<sys:String x:Key="text.info">資訊</sys:String>
<sys:String x:Key="text.ok">確定</sys:String>
<sys:String x:Key="text.cancel">取消</sys:String>
<sys:String x:Key="text.not_available">不可使用</sys:String>
<sys:String x:Key="text.connect">連接</sys:String>
<sys:String x:Key="text.remove">移除</sys:String>
<sys:String x:Key="text.delete">刪除</sys:String>
<sys:String x:Key="text.add">新增</sys:String>
<sys:String x:Key="text.server.connect.ing">正在連接伺服器...</sys:String>
<sys:String x:Key="text.server.connect.fail">連接伺服器失敗!</sys:String>
<sys:String x:Key="text.server.connect.fail.text">無法連接到遠程伺服器:%s\n請檢查伺服器RCON地址配置是否正確,以及檢查服務端是否開啟了RCON選項!</sys:String>
<sys:String x:Key="text.server.connect.auth_fail">Rcon密碼錯誤,請檢查您的伺服器密碼是否正確!</sys:String>
<sys:String x:Key="text.server.connected">連接伺服器並認證成功!</sys:String>
<sys:String x:Key="text.server.closed">連接已斷開!</sys:String>
<sys:String x:Key="text.server.start">開始連接</sys:String>
<sys:String x:Key="text.server.not_connect.text">無法連接到伺服器,因此無法使用遠程命令功能,請嘗試回到伺服器列表重新連接到本伺服器!</sys:String>
<sys:String x:Key="text.server_information.error.json_error">無法解析伺服器列表 /servers.json %s\n點選"是"重置伺服器列表(需重新添加伺服器,但記錄的密碼不會消失)\n點選"取消"關閉程式!</sys:String>
<sys:String x:Key="text.server_information.error.text">無法解析伺服器列表 /servers.json %s\n點選"是"關閉程式!</sys:String>
<sys:String x:Key="text.server_information.error.save">無法儲存檔案 /servers.json\n如果您剛剛進行了添加伺服器操作,請注意,本次儲存並未生效!\n%s</sys:String>
<sys:String x:Key="text.password.error.json_error">無法解析密碼列表 /passwords.json %s\n點選"是"重置密碼列表(需重新設定密碼,但記錄的伺服器不會消失)\n點選"取消"關閉程式!</sys:String>
<sys:String x:Key="text.password.error.text">無法解析密碼列表 /passwords.json %s\n點選"是"關閉程式!</sys:String>
<sys:String x:Key="text.password.error.save">無法儲存檔案 /passwords.json\n如果您剛剛進行了設定密碼操作,請注意,本次儲存並未生效!\n%s</sys:String>
<sys:String x:Key="text.config.json_error">無法解析配置檔案 /config.json JSON解析失敗:%s\n點選"是"重置配置檔案!\n點選"否"退出程式!</sys:String>
<sys:String x:Key="text.config.error">無法解析配置檔案 /config.json:%s\n點選"是"重置配置檔案!\n點選"否"退出程式!</sys:String>
<sys:String x:Key="text.config.save_error">無法儲存配置檔案 /config.json:%s\n如果您剛剛更改了配置檔案,請注意,儲存並未生效!</sys:String>
<sys:String x:Key="groups.exception.invalid_data_exception">讀取和解析組檔案"{0}"時發生錯誤,請嘗試刪除或修復檔案以解決此錯誤!</sys:String>
<sys:String x:Key="groups.exception.same_group_id_exception">相同的 GroupId 已存在(現有值: {0},重複值: {1})</sys:String>
<sys:String x:Key="groups.exception.same_name_exception">相同的 Name 已存在(現有Id: {0},重複Id: {1})</sys:String>
<sys:String x:Key="groups.exception.group_id_exists_exception">檔案中已存在具有相同內部 ID 的分組,請再次嘗試建立</sys:String>
<sys:String x:Key="groups.exception.file_name_mismatch_exception">{0} 檔案名與內部 ID {1} 不匹配</sys:String>
<sys:String x:Key="groups.exception.name_already_exists_exception">相同的組名已存在</sys:String>
<sys:String x:Key="ui.group.no_group_title">點擊「+添加」添加一個分組吧!</sys:String>
<sys:String x:Key="ui.group.no_group_subtitle">添加分組後,您可以將命令廣播到該分組的所有伺服器</sys:String>
<sys:String x:Key="ui.group.no_server">該分組沒有任何伺服器,請點擊「+添加」添加一個伺服器吧!</sys:String>
<sys:String x:Key="ui.group.delete_group">是否要刪除分組 {0}?</sys:String>
<sys:String x:Key="ui.add_group.title">新建分組</sys:String>
<sys:String x:Key="ui.add_group.placeholder_text">分組名稱</sys:String>
<sys:String x:Key="ui.join_group.title">選擇伺服器</sys:String>
<sys:String x:Key="ui.join_group.no_server">沒有可用的伺服器</sys:String>
<sys:String x:Key="service.rcon.offline">離線</sys:String>
</ResourceDictionary>
================================================
FILE: NectarRCON/Services/ApplicationHostService.cs
================================================
using Microsoft.Extensions.Hosting;
using NectarRCON.Core.Helper;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Extensions.Logging;
using Serilog;
using Wpf.Ui.Mvvm.Contracts;
namespace NectarRCON.Services;
public class ApplicationHostService(
IServiceProvider serviceProvider,
INavigationService navigationService,
IThemeService themeService,
ILanguageService languageService,
IConfigService configService)
: IHostedService
{
private readonly INavigationService _navigationService = navigationService;
private INavigationWindow? _navigationWindow;
public async Task StartAsync(CancellationToken cancellationToken)
{
Log.Information("Starting NectarRCON...");
await HandleActivationAsync();
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await Task.CompletedTask;
}
private void LoadConfig()
{
switch (configService.GetConfig().Theme)
{
case ETheme.System:
themeService.SetTheme(Win32Helper.GetWindowsTheme() ? Wpf.Ui.Appearance.ThemeType.Dark : Wpf.Ui.Appearance.ThemeType.Light);
break;
case ETheme.Dark:
themeService.SetTheme(Wpf.Ui.Appearance.ThemeType.Dark);
break;
case ETheme.Light:
themeService.SetTheme(Wpf.Ui.Appearance.ThemeType.Light);
break;
default:
break;
}
if (configService.GetConfig().LanguageName == string.Empty)
{
languageService.SelectLanguage();
configService.GetConfig().LanguageName = languageService.GetKey("file.language");
configService.Save();
}
else
{
languageService.SelectLanguage(configService.GetConfig().LanguageName, false);
}
}
private async Task HandleActivationAsync()
{
await Task.CompletedTask;
if (!Application.Current.Windows.OfType<Container>().Any())
{
_navigationWindow = (serviceProvider.GetService(typeof(INavigationWindow)) as INavigationWindow)!;
Log.Information("Show MainWindow...");
_navigationWindow!.ShowWindow();
}
LoadConfig();
await Task.CompletedTask;
}
}
================================================
FILE: NectarRCON/Services/ConfigService.cs
================================================
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System;
using System.Diagnostics;
using System.IO;
using System.Text.Json;
using System.Windows;
namespace NectarRCON.Services;
public partial class ConfigService : IConfigService
{
private ILanguageService _languageService;
private Config _config = new();
public ConfigService(ILanguageService languageService)
{
_languageService = languageService;
if (!File.Exists("./config.json"))
Save();
try
{
_config = JsonSerializer.Deserialize<Config>(File.ReadAllText("./config.json"))
?? new Config();
}
catch (Exception ex)
{
var resutl = MessageBox.Show(_languageService.GetKey(ex.GetType() == typeof(JsonException) ? "text.config.json_error" : "text.config.error")
.Replace("%s", ex.Message), _languageService.GetKey("text.error"), MessageBoxButton.YesNo, MessageBoxImage.Error);
if (resutl == MessageBoxResult.Yes)
{
_config = new();
Save();
}
else
{
Process.GetCurrentProcess().Kill();
}
}
}
public Config GetConfig()
=> _config;
public void Save()
{
try
{
File.WriteAllText("./config.json", JsonSerializer.Serialize(_config));
}
catch (Exception ex)
{
MessageBox.Show(_languageService.GetKey("text.config.save_error")
.Replace("%s", ex.Message), _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
================================================
FILE: NectarRCON/Services/ConnectingDialogService.cs
================================================
using NectarRCON.Interfaces;
using System.Windows;
using System.Windows.Controls;
namespace NectarRCON.Services;
internal class ConnectingDialogService : IConnectingDialogService
{
private Grid? _dialog;
public void Close()
{
if (null == _dialog)
return;
_dialog.Visibility = Visibility.Hidden;
}
public void SetDialog(Grid grid)
{
_dialog = grid;
}
public void Show()
{
if (null == _dialog)
return;
_dialog.Visibility = Visibility.Visible;
}
}
================================================
FILE: NectarRCON/Services/GroupService.cs
================================================
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
namespace NectarRCON.Services
{
public class GroupService : IGroupService
{
private static string _groupPath = Path.Combine("./groups");
private readonly IMessageBoxService _messageBoxService;
private readonly ILanguageService _languageService;
private readonly Dictionary<string, Group> _groupMapping = new(); // id, group
private readonly Dictionary<string, Group> _groupNameMapping = new(); // name, group
public GroupService(IMessageBoxService messageBoxService, ILanguageService languageService)
{
_messageBoxService = messageBoxService;
Refresh();
_languageService = languageService;
}
private void Refresh()
{
_groupMapping.Clear();
_groupNameMapping.Clear();
if (Directory.Exists(_groupPath))
{
string[] jsonFiles = Directory.GetFiles(_groupPath, "*.json");
foreach (string jsonFile in jsonFiles)
{
try
{
using (FileStream fs = File.OpenRead(jsonFile))
{
Group group = JsonSerializer.Deserialize<Group>(fs) ?? throw new InvalidDataException(jsonFile);
if (group.Id.ToLower() != Path.GetFileNameWithoutExtension(jsonFile).ToLower())
throw new InvalidDataException(string.Format(_languageService.GetKey("groups.exception.file_name_mismatch_exception"), jsonFile, group.Id));
if (_groupMapping.ContainsKey(group.Id))
throw new InvalidDataException(string.Format(_languageService.GetKey("groups.exception.same_group_id_exception"), _groupMapping[group.Id].Name, group.Name));
if (_groupNameMapping.ContainsKey(group.Name))
throw new InvalidDataException(string.Format(_languageService.GetKey("groups.exception.same_name_exception"), _groupMapping[group.Id].Id, group.Id));
_groupMapping.Add(group.Id, group);
_groupNameMapping.Add(group.Name, group);
}
}
catch (Exception ex)
{
_messageBoxService.Show(ex.Message, string.Format(_languageService.GetKey("groups.exception.invalid_data_exception"), ex.ToString()));
}
}
}
else
{
Directory.CreateDirectory(_groupPath);
}
}
private void RemoveGroupInDict(string groupId)
{
if (_groupMapping.TryGetValue(groupId, out Group? group))
{
_groupMapping.Remove(groupId);
if (_groupNameMapping.ContainsKey(group.Name))
{
_groupNameMapping.Remove(group.Name);
}
}
}
public string Add(Group group)
{
string filePath = Path.Combine(_groupPath, group.Id + ".json");
if (!File.Exists(filePath))
{
if (_groupNameMapping.ContainsKey(group.Name))
throw new InvalidOperationException(_languageService.GetKey("groups.exception.name_already_exists_exception"));
if (_groupMapping.ContainsKey(group.Id))
throw new InvalidOperationException(_languageService.GetKey("groups.exception.group_id_exists_exception"));
File.WriteAllBytes(filePath, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(group)));
_groupMapping.Add(group.Id, group);
_groupNameMapping.Add(group.Name,group);
return group.Id;
}
throw new InvalidOperationException(_languageService.GetKey("groups.exception.group_id_exists_exception"));
}
public void Delete(string groupId)
{
string filePath = Path.Combine(_groupPath, groupId + ".json");
if (File.Exists(filePath))
{
File.Delete(filePath);
RemoveGroupInDict(groupId);
}
}
public Group? FindGroup(string name)
{
_groupNameMapping.TryGetValue(name, out Group? group);
return group;
}
public Group? GetGroup(string groupId)
{
_groupMapping.TryGetValue(groupId, out Group? group);
return group;
}
public IReadOnlyList<Group> GetGroups()
=> _groupMapping.Select(s => s.Value).ToList();
}
}
================================================
FILE: NectarRCON/Services/HistoryService.cs
================================================
using NectarRCON.Interfaces;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace NectarRCON.Services;
public class HistoryService : IHistoryService
{
/// <summary>
/// 双向链表保存历史记录
/// </summary>
private HistoryNode? _head;
private HistoryNode? _tail;
private readonly Dictionary<string, HistoryNode> _map;
/// <summary>
/// 限制记录条数
/// </summary>
private int _limit = 20;
public HistoryService()
{
_map = [];
if (!Path.Exists("./logs"))
{
Directory.CreateDirectory("./logs");
}
var stream = File.Open($"./logs/history", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
using StreamReader reader = new StreamReader(stream);
string? line;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (!string.IsNullOrEmpty(line))
{
AppendNode(line);
}
}
}
public HistoryNode? InputCmd(string cmd)
{
var node = AppendNode(cmd);
Save();
return node;
}
private HistoryNode? AppendNode(string cmd)
{
cmd = cmd.Trim();
HistoryNode node;
if (_map.ContainsKey(cmd))
{
// 已存在的记录,将其移动到链表尾部
node = _map[cmd];
if (node == _tail)
{
return null;
}
else if (node == _head)
{
_head = _head.Next;
}
if (node.Prev != null)
{
node.Prev.Next = node.Next;
}
if (node.Next != null)
{
node.Next.Prev = node.Prev;
}
node.Prev = null;
node.Next = null;
}
else
{
node = new HistoryNode()
{
Cmd = cmd,
};
_map.Add(cmd, node);
}
if (_head == null || _tail == null)
{
_head = _tail = node;
}
else
{
_tail.Next = node;
node.Prev = _tail;
_tail = node;
}
// 超出限制,移除链表头部记录
if (_map.Count() > _limit)
{
var head = _head;
_head = _head.Next;
if (_head != null)
{
_head.Prev = null;
}
if (!string.IsNullOrEmpty(head.Cmd))
{
_map.Remove(head.Cmd);
}
}
return null;
}
public HistoryNode? Next(HistoryNode? current)
{
if (current == null)
{
return null;
}
return current.Next;
}
public HistoryNode? Prev(HistoryNode? current)
{
if (current == null)
{
return _tail;
}
else if (current.Prev == null)
{
return current;
}
return current.Prev;
}
private void Save()
{
using var stream = File.Open($"./logs/history", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
stream.Seek(0, SeekOrigin.Begin);
HistoryNode? node = _head;
while (node != null) {
if (!string.IsNullOrEmpty(node.Cmd))
{
string cmd = node.Cmd + "\n";
stream.Write(Encoding.UTF8.GetBytes(cmd));
}
node = node.Next;
}
}
}
================================================
FILE: NectarRCON/Services/LanguageService.cs
================================================
using NectarRCON.Interfaces;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
namespace NectarRCON.Services;
public class LanguageService : ILanguageService
{
private readonly Dictionary<string, string> _defaultLanguages = new();
private Dictionary<string, ResourceDictionary> _languages = new();
private ResourceDictionary _selectedLanguage = new ResourceDictionary()
{
Source = new Uri("pack://application:,,,/NectarRCON;component/Resources/Languages/zh_cn.xaml", UriKind.RelativeOrAbsolute)
};
private readonly ResourceDictionary _defLanguage = new ResourceDictionary()
{
Source = new Uri("pack://application:,,,/NectarRCON;component/Resources/Languages/zh_cn.xaml", UriKind.RelativeOrAbsolute)
};
public LanguageService()
{
Refresh();
}
public ResourceDictionary SelectedLanguage
{
get => _selectedLanguage;
}
public Dictionary<string, ResourceDictionary> Languages
{
get => _languages;
}
public Dictionary<string, ResourceDictionary> GetLanguages()
=> Languages;
public ResourceDictionary GetSelectedLanguage()
{
return _selectedLanguage;
}
public void Refresh()
{
_languages.Clear();
// 从本地目录获取xaml
string[] files = new string[0];
if (Directory.Exists("./languages/"))
files = Directory.GetFiles("./languages/");
foreach (string file in files)
{
if (Path.GetExtension(file).ToLower() == ".xaml" || Path.GetExtension(file).ToLower() == ".xml")
{
ResourceDictionary resourceDictionary = new ResourceDictionary();
using (FileStream fs = File.OpenRead(file))
{
resourceDictionary = (ResourceDictionary)System.Windows.Markup.XamlReader.Load(fs);
}
_languages.Add(Path.GetFileNameWithoutExtension(file), resourceDictionary);
}
}
// 从内部文件加载
_defaultLanguages.Add("zh_cn", "pack://application:,,,/NectarRCON;component/Resources/Languages/zh_cn.xaml");
_defaultLanguages.Add("zh_tw", "pack://application:,,,/NectarRCON;component/Resources/Languages/zh_tw.xaml");
_defaultLanguages.Add("en_us", "pack://application:,,,/NectarRCON;component/Resources/Languages/en_us.xaml");
foreach (KeyValuePair<string, string> language in _defaultLanguages)
{
if (_languages.ContainsKey(language.Key))
_languages.Remove(language.Key);
Languages.Add(language.Key, new ResourceDictionary()
{
Source = new Uri(language.Value, UriKind.RelativeOrAbsolute)
});
}
}
public void SelectLanguage()
{
Application.Current.Resources.Remove(SelectedLanguage);
string name = System.Globalization.CultureInfo.CurrentCulture.Name;
SelectLanguage(name);
}
public void SelectLanguage(string languageName, bool name = false)
{
languageName = languageName.Replace("-", "_");
Application.Current.Resources.MergedDictionaries.Remove(SelectedLanguage);
var language = Languages.Where(l =>
{
if (name)
{
return (l.Value["file.name"].ToString() ?? "nullname") == languageName.ToLower();
}
else
{
return l.Key.ToLower() == languageName.ToLower();
}
}).FirstOrDefault();
if (null == language.Value)
{
_selectedLanguage = new ResourceDictionary()
{
Source = new Uri("pack://application:,,,/NectarRCON;component/Resources/Languages/en_us.xaml", UriKind.RelativeOrAbsolute)
};
if (Application.Current.Resources.Contains("en_us"))
{
Application.Current.Resources.Remove("en_us");
}
Application.Current.Resources.MergedDictionaries.Add(_selectedLanguage);
}
else
{
_selectedLanguage = language.Value;
Application.Current.Resources.MergedDictionaries.Add(language.Value);
}
}
public string GetKey(string key)
{
string valuel;
if (_selectedLanguage.Contains(key))
valuel = _selectedLanguage[key].ToString() ?? string.Empty;
else if (_defLanguage.Contains(key))
valuel = _defLanguage[key].ToString() ?? string.Empty;
else valuel = key;
return valuel
.Replace("\\n", "\n");
}
}
================================================
FILE: NectarRCON/Services/LogService.cs
================================================
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.RegularExpressions;
using System.Windows;
namespace NectarRCON.Services;
public class LogService : ILogService
{
private FileStream? _logFileStream;
public LogService()
{
if (!Path.Exists("./logs"))
Directory.CreateDirectory("./logs");
}
public void Clear()
{
_logFileStream?.SetLength(0);
_logFileStream?.Flush();
}
public string GetText()
{
using (MemoryStream ms = new MemoryStream())
{
_logFileStream?.CopyTo(ms);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
public string Log(string message)
{
string logText = $"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}] {message}\n";
_logFileStream?.Write(Encoding.UTF8.GetBytes(logText));
_logFileStream?.Flush();
return logText;
}
public void SetServer(ServerInformation server)
{
OpenFile("server_" + UrlEncoder.Default.Encode(server.Name));
}
public void SetGroup(string groupId)
{
OpenFile("group_" + UrlEncoder.Default.Encode(groupId));
}
private void OpenFile(string fileName)
{
if (!File.Exists($"./logs/{fileName}.log"))
File.Create($"./logs/{fileName}.log").Close();
_logFileStream?.Close();
_logFileStream?.Dispose();
_logFileStream = File.Open($"./logs/{fileName}.log", FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
}
}
================================================
FILE: NectarRCON/Services/MessageBoxService.cs
================================================
using NectarRCON.Interfaces;
using System;
using System.Windows;
namespace NectarRCON.Services;
public class MessageBoxService : IMessageBoxService
{
private readonly ILanguageService _languageService;
public MessageBoxService(ILanguageService languageService)
{
_languageService = languageService;
}
public void Show(string message)
=> MessageBox.Show(message, "NectarRcon", MessageBoxButton.OK, MessageBoxImage.Information);
public void Show(string message, string title)
=> MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Information);
public MessageBoxResult Show(string message, string title, MessageBoxButton button)
=> MessageBox.Show(message, title, button, MessageBoxImage.Information);
public void Show(string message, string title, MessageBoxImage image)
=> MessageBox.Show(message, title, MessageBoxButton.OK, image);
public MessageBoxResult Show(string message, string title, MessageBoxButton button, MessageBoxImage image)
=> MessageBox.Show(message, title, button, image);
public void Show(Exception exception, string? information = null)
=> MessageBox.Show($"{_languageService.GetKey("text.went_wrong")}\n{information}\n{exception}", "error", MessageBoxButton.OK, MessageBoxImage.Error);
}
================================================
FILE: NectarRCON/Services/RconConnectionInfoService.cs
================================================
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace NectarRCON.Services;
/// <summary>
/// Rcon连接信息管理服务
/// </summary>
public class RconConnectionInfoService : IRconConnectionInfoService
{
private readonly IServerInformationService _serverInformationService;
private readonly List<ServerInformation> _serverInformation = new();
public RconConnectionInfoService(IServerInformationService serverInformationService)
{
_serverInformationService = serverInformationService;
}
public void AddInformation(string serverName)
=> _serverInformation.Add(_serverInformationService.GetServer(serverName) ?? throw new ArgumentNullException(nameof(serverName)));
public void Clear()
=> _serverInformation.Clear();
public IReadOnlyList<ServerInformation> GetInformation()
=> _serverInformation;
public ServerInformation? GetLastInformation()
=> _serverInformation.FirstOrDefault();
}
================================================
FILE: NectarRCON/Services/ServerInformationService.cs
================================================
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Windows;
namespace NectarRCON.Services;
public class ServerInformationService : IServerInformationService
{
private readonly ILanguageService _languageService;
private List<ServerInformation> _servers = new();
public List<ServerInformation> Servers
=> _servers;
public ServerInformationService(ILanguageService languageService)
{
_languageService = languageService;
if (!File.Exists("./servers.json"))
File.WriteAllText("./servers.json", "[]");
try
{
string jsonString = File.ReadAllText("./servers.json");
_servers = JsonSerializer.Deserialize<List<ServerInformation>>(jsonString)
?? new List<ServerInformation>();
}
catch (JsonException ex)
{
MessageBoxResult result = MessageBox.Show(_languageService.GetKey("text.server_information.error.json_error")
.Replace("%s", ex.Message)
.Replace("\\n", "\n"), _languageService.GetKey("text.error"), MessageBoxButton.OKCancel, MessageBoxImage.Error);
if (result == MessageBoxResult.OK)
File.WriteAllText("./servers.json", "[]");
else
Process.GetCurrentProcess().Kill();
}
catch (Exception ex)
{
MessageBox.Show(_languageService.GetKey("text.server_information.error.text")
.Replace("%s", ex.Message)
.Replace("\\n", "\n")
, _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
Process.GetCurrentProcess().Kill();
}
}
public void AddServer(ServerInformation server)
{
if (ServerIsExist(server.Name))
return;
_servers.Add(server);
}
public ServerInformation? GetServer(string name)
=> _servers.Where(s => s.Name == name).FirstOrDefault();
public List<ServerInformation> GetServers()
{
return _servers;
}
public void RemoveServer(string name)
{
ServerInformation? server = GetServer(name);
if (null == server) return;
_servers.Remove(server);
}
public void Save()
{
try
{
File.WriteAllText("./servers.json", JsonSerializer.Serialize(_servers));
}
catch (Exception ex)
{
MessageBox.Show(_languageService.GetKey("text.server_information.error.save")
.Replace("%s", ex.Message)
.Replace("\\n", "\n")
, _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public bool ServerIsExist(string name)
=> GetServer(name) != null;
public void Update(string name, ServerInformation newInfo)
{
var oldInfo = GetServer(name);
if (null == oldInfo) return;
for (int i = 0; i < _servers.Count; i++)
{
if (_servers[i] == oldInfo)
{
_servers[i] = newInfo;
return;
}
}
}
}
================================================
FILE: NectarRCON/Services/ServerPasswordService.cs
================================================
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Windows;
namespace NectarRCON.Services;
public class ServerPasswordService : IServerPasswordService
{
private readonly ILanguageService _languageService;
private ServerInformation? _selectedServer;
private List<ServerPassword> _serverPasswordList = new();
public ServerPasswordService(ILanguageService languageService)
{
_languageService = languageService;
if (!File.Exists("./passwords.json"))
File.WriteAllText("./passwords.json", "[]");
try
{
string jsonString = File.ReadAllText("./passwords.json");
_serverPasswordList = JsonSerializer.Deserialize<List<ServerPassword>>(jsonString)
?? new List<ServerPassword>();
}
catch (JsonException ex)
{
MessageBoxResult result = MessageBox.Show(_languageService.GetKey("text.password.error.json_error")
.Replace("%s", ex.Message)
.Replace("\\n", "\n"), _languageService.GetKey("text.error"), MessageBoxButton.OKCancel, MessageBoxImage.Error);
if (result == MessageBoxResult.OK)
File.WriteAllText("./passwords.json", "[]");
else
Process.GetCurrentProcess().Kill();
}
catch (Exception ex)
{
MessageBox.Show(_languageService.GetKey("text.password.error.text")
.Replace("%s", ex.Message)
.Replace("\\n", "\n")
, _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
Process.GetCurrentProcess().Kill();
}
}
public ServerPassword? Get(ServerInformation server)
{
var password = _serverPasswordList.Where(s =>
{
return s.ServerName == server.Name;
}).FirstOrDefault();
return password;
}
public ServerInformation GetSelect()
{
return _selectedServer ?? new();
}
public bool IsExist(ServerInformation server)
=> Get(server) != null;
public void Remove(ServerInformation server)
{
ServerPassword? password = Get(server);
if (password == null)
return;
_serverPasswordList.Remove(password);
}
public void Save()
{
try
{
File.WriteAllText("./passwords.json", JsonSerializer.Serialize(_serverPasswordList));
}
catch (Exception ex)
{
MessageBox.Show(_languageService.GetKey("text.password.error.save")
.Replace("%s", ex.Message)
.Replace("\\n", "\n")
, _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void Select(ServerInformation server)
{
_selectedServer = server;
}
public void Set(ServerInformation server, string? password, bool? isEmpty)
{
var oldPassword = Get(server);
ServerPassword newPassword;
if (oldPassword == null)
{
newPassword = new ServerPassword()
{
Password = password ?? string.Empty,
IsEmpty = isEmpty ?? string.IsNullOrEmpty(password),
ServerName = server.Name
};
}
else
{
newPassword = new ServerPassword()
{
Password = password ?? oldPassword.Password,
IsEmpty = isEmpty ?? oldPassword.IsEmpty,
ServerName = server.Name
};
}
if (IsExist(server))
_serverPasswordList.Remove(Get(server)!);
_serverPasswordList.Add(newPassword);
}
}
================================================
FILE: NectarRCON/ViewModels/AboutPageViewModel.cs
================================================
namespace NectarRCON.ViewModels
{
class AboutPageViewModel
{
}
}
================================================
FILE: NectarRCON/ViewModels/AddGroupPageViewModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Services;
using System;
using Wpf.Ui.Mvvm.Contracts;
namespace NectarRCON.ViewModels;
public partial class AddGroupPageViewModel:ObservableObject
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(AddCommand))]
private string? _groupName;
private INavigationService _navigationService;
private IMessageBoxService _messageBoxService;
private IGroupService _groupService;
public AddGroupPageViewModel()
{
GroupName = string.Empty;
_navigationService = App.GetService<INavigationService>();
_messageBoxService = App.GetService<IMessageBoxService>();
_groupService = App.GetService<IGroupService>();
}
private bool CanAdd()
=> !string.IsNullOrWhiteSpace(GroupName);
[RelayCommand(CanExecute = nameof(CanAdd))]
public void Add()
{
try
{
_groupService.Add(new Models.Group()
{
Id = Guid.NewGuid().ToString(),
Name = GroupName!,
Servers = new()
});
_navigationService.Navigate(4);
}catch(Exception ex)
{
_messageBoxService.Show(ex, string.Empty);
}
}
[RelayCommand]
public void Cancel()
{
_navigationService.Navigate(4);
}
[RelayCommand]
public void Load()
{
GroupName = null;
}
}
================================================
FILE: NectarRCON/ViewModels/AddServerWindowViewModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using NectarRCON.Windows;
using System.Windows;
namespace NectarRCON.ViewModels;
public partial class AddServerWindowViewModel : ObservableObject
{
private readonly IServerInformationService _serverInformationService;
private readonly ILanguageService _languageService;
private AddServerWindow? _serverWindow;
[ObservableProperty]
private string _serverName = "Rcon";
[ObservableProperty]
private string _serverAddress = "localhost";
[ObservableProperty]
private string _serverPort = "25575";
public AddServerWindowViewModel(IServerInformationService serverInformationService, ILanguageService languageService)
{
_serverInformationService = serverInformationService;
_languageService = languageService;
}
public void SetWindow(AddServerWindow window)
{
_serverWindow = window;
}
[RelayCommand]
private void Ok()
{
ServerAddress = ServerAddress.Trim();
if (string.IsNullOrWhiteSpace(ServerName) || string.IsNullOrWhiteSpace(ServerAddress))
{
MessageBox.Show(_languageService.GetKey("ui.add_server_window.null_text"), _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
var information = new ServerInformation()
{
Name = ServerName,
Address = ServerAddress,
Port = ushort.Parse(ServerPort)
};
if (_serverInformationService.ServerIsExist(information.Name))
{
MessageBox
.Show(_languageService.GetKey("ui.add_server_window.already_exist")
, _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
}
else
{
_serverInformationService.AddServer(information);
_serverInformationService.Save();
_serverWindow?.Close();
}
}
}
================================================
FILE: NectarRCON/ViewModels/EditPasswordWindowViewModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using NectarRCON.Windows;
namespace NectarRCON.ViewModels;
public partial class EditPasswordWindowViewModel : ObservableObject
{
private readonly IServerPasswordService _serverPasswordService;
private readonly ServerInformation _serverInformation;
private EditPasswordWindow? _window = null;
[ObservableProperty]
private string _password = string.Empty;
[ObservableProperty]
private bool _isEmpty = true;
public EditPasswordWindowViewModel()
{
_serverPasswordService = App.GetService<IServerPasswordService>();
_serverInformation = _serverPasswordService.GetSelect()!;
var password = _serverPasswordService.Get(_serverInformation);
if (password != null)
{
Password = password.Password;
IsEmpty = string.IsNullOrEmpty(Password);
}
else
{
Password = string.Empty;
IsEmpty = true;
}
}
public void SetWindow(EditPasswordWindow window)
{
_window = window;
}
[RelayCommand]
public void TextChange()
{
IsEmpty = string.IsNullOrEmpty(Password);
}
[RelayCommand]
public void SetPassword()
{
_serverPasswordService.Set(_serverInformation, Password, IsEmpty);
_serverPasswordService.Save();
_window?.Close();
}
}
================================================
FILE: NectarRCON/ViewModels/EditServerWindowViewModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System.Windows;
using Wpf.Ui.Controls;
using MessageBox = System.Windows.MessageBox;
namespace NectarRCON.ViewModels;
public partial class EditServerWindowViewModel : ObservableObject
{
private readonly ILanguageService _languageService;
private readonly IServerPasswordService _serverPasswordService;
private readonly IServerInformationService _serverInformationService;
private UiWindow? _window;
[ObservableProperty]
private ServerInformation? _selectServer;
[ObservableProperty]
private string _port = string.Empty;
[ObservableProperty]
private string _address = string.Empty;
public EditServerWindowViewModel()
{
_languageService = App.GetService<ILanguageService>();
_serverPasswordService = App.GetService<IServerPasswordService>();
_serverInformationService = App.GetService<IServerInformationService>();
}
[RelayCommand]
private void Load(RoutedEventArgs e)
{
_window = e.Source as UiWindow;
SelectServer = _serverPasswordService.GetSelect();
Port = _selectServer?.Port.ToString() ?? "0";
Address = _selectServer?.Address ?? "localhost";
}
[RelayCommand]
public void Exit()
{
_window?.Close();
}
[RelayCommand]
private void Ok()
{
Address = Address.Trim();
if (string.IsNullOrWhiteSpace(_selectServer?.Address) || string.IsNullOrEmpty(Address))
MessageBox.Show(_languageService.GetKey("ui.add_server_window.null_text"), _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
else
{
_selectServer.Port = ushort.Parse(Port);
_selectServer.Address = Address;
_serverInformationService.Update(_selectServer.Name, _selectServer);
_serverInformationService.Save();
Exit();
}
}
}
================================================
FILE: NectarRCON/ViewModels/GroupPageViewModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using NectarRCON.Views.Pages;
using System.Collections.ObjectModel;
using Wpf.Ui.Mvvm.Contracts;
namespace NectarRCON.ViewModels;
public partial class GroupPageViewModel:ObservableObject
{
[ObservableProperty]
private ObservableCollection<GroupModel> _groups;
private readonly IGroupService _groupService;
private readonly ILanguageService _languageService;
private readonly IMessageBoxService _messageBoxService;
private readonly INavigationService _navigationService;
#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
public GroupPageViewModel()
#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
{
_groupService = App.GetService<IGroupService>();
_languageService = App.GetService<ILanguageService>();
_messageBoxService = App.GetService<IMessageBoxService>();
_navigationService = App.GetService<INavigationService>();
Groups = new();
}
[RelayCommand]
public void Load()
{
Refresh();
}
private void Refresh()
{
Groups.Clear();
foreach(Group group in _groupService.GetGroups())
{
Groups.Add(new(group.Name, this));
}
}
[RelayCommand]
public void RemoveGroup(string groupId)
{
Group group = _groupService.GetGroup(groupId)!;
if (_messageBoxService.Show(string.Format(_languageService.GetKey("ui.group.delete_group"), group.Name), _languageService.GetKey("text.delete"), System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Question)
== System.Windows.MessageBoxResult.Yes)
{
_groupService.Delete(groupId);
Refresh();
}
}
[RelayCommand]
public void NewGroup()
{
_navigationService.Navigate(typeof(AddGroupPage));
}
}
================================================
FILE: NectarRCON/ViewModels/JoinGroupWindowViewModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using NectarRCON.Interfaces;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Data;
namespace NectarRCON.ViewModels;
public partial class JoinGroupWindowViewModel:ObservableObject
{
private IServerInformationService _serverInformationService;
[ObservableProperty]
private ObservableCollection<string> _servers = new();
[ObservableProperty]
private ListCollectionView? _serverCollectionView;
[ObservableProperty]
public ObservableCollection<string>? _blackList;
public JoinGroupWindowViewModel()
{
_serverInformationService = App.GetService<IServerInformationService>();
foreach(var server in _serverInformationService.GetServers())
{
Servers.Add(server.Name);
}
ServerCollectionView = new(Servers);
ServerCollectionView.Filter += (s) =>
{
return !BlackList?.Contains(s?.ToString() ?? string.Empty) ?? true;
};
BlackList = new();
}
partial void OnBlackListChanged(ObservableCollection<string>? value)
{
ServerCollectionView?.Refresh();
}
}
================================================
FILE: NectarRCON/ViewModels/MainPageViewModel.cs
================================================
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using NectarRCON.Rcon;
using NectarRCON.Services;
using NectarRCON.Views.Pages;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using NectarRCON.Dp;
using Serilog;
using Wpf.Ui.Mvvm.Contracts;
using MessageBox = System.Windows.MessageBox;
using TextBox = Wpf.Ui.Controls.TextBox;
namespace NectarRCON.ViewModels;
public partial class MainPageViewModel : ObservableObject
{
private static readonly RconSettingsDp RconSettings = DpFile.LoadSingleton<RconSettingsDp>();
private readonly ILogService _logService;
private readonly IHistoryService _historyService;
private readonly IServerPasswordService _serverPasswordService;
private IRconConnection _rconConnectService;
private readonly INavigationService _navigationService;
private readonly ILanguageService _languageService;
private readonly IRconConnectionInfoService _rconConnectionInfoService;
private readonly IConnectingDialogService _connectingDialogService;
private readonly IMessageBoxService _messageBoxService;
private MainPage? _page;
private TextBox? _logTextBox;
private HistoryNode? _historyNode;
[ObservableProperty] private string _commandText = string.Empty;
[ObservableProperty] private string _logText = string.Empty;
[ObservableProperty] private bool _isMultipleConnection;
[ObservableProperty] private bool _isDisconnection;
public MainPageViewModel()
{
_logService = App.GetService<ILogService>();
_historyService = App.GetService<IHistoryService>();
_serverPasswordService = App.GetService<IServerPasswordService>();
_navigationService = App.GetService<INavigationService>();
_languageService = App.GetService<ILanguageService>();
_rconConnectionInfoService = App.GetService<IRconConnectionInfoService>();
_messageBoxService = App.GetService<IMessageBoxService>();
_connectingDialogService = App.GetService<IConnectingDialogService>();
WeakReferenceMessenger.Default.Register<ClearLogValueMessage>(this, OnClear);
// 选择连接服务
_rconConnectService = _rconConnectionInfoService.HasMultipleInformation
? App.GetService<IRconConnection>(typeof(RconMultiConnection))
: App.GetService<IRconConnection>(typeof(RconSingleConnection));
IsMultipleConnection = _rconConnectionInfoService.HasMultipleInformation;
}
private void OnClear(object sender, ClearLogValueMessage msg)
{
_logService.Clear();
LogText = string.Empty;
}
private void OnMessage(ServerInformation info, string msg)
{
Log.Information("[OnMessage] {name}({adapter}) -> {msg}", info.Name, string.IsNullOrEmpty(info.Adapter) ? "TCPRcon" : info.Adapter, string.IsNullOrEmpty(msg) ? "$empty$" : msg);
string logMsg = string.IsNullOrEmpty(msg)
? _languageService.GetKey("ui.main_page.successful")
: msg;
LogText += _logService.Log($"{info.Name}:" + logMsg);
_logTextBox?.ScrollToEnd();
}
private void OnClosed(ServerInformation info)
{
LogText += _logService.Log($"{info.Name} {_languageService.GetKey("text.server.closed")}");
IsDisconnection = !_rconConnectService.IsConnected();
}
[RelayCommand]
private async void Load(RoutedEventArgs e)
{
// GetLogs
LogText = string.Empty;
LogText = _logService.GetText();
_page = e.Source as MainPage;
await ConnectAsync();
}
[RelayCommand]
private async void ReConnect()
{
Log.Information($"[ReConnectCommand] 正在准备重连");
if (_rconConnectService.IsConnected())
_rconConnectService.Close();
IsDisconnection = false;
await ConnectAsync();
}
private async Task ConnectAsync()
{
Log.Information($"[ConnectAsync] 准备连接到服务器");
IsMultipleConnection = _rconConnectionInfoService.HasMultipleInformation;
_rconConnectService.OnConnected -= OnConnected;
_rconConnectService.OnMessage -= OnMessage;
_rconConnectService.OnClosed -= OnClosed;
await Task.CompletedTask;
try
{
_connectingDialogService.Show();
// 选择连接服务
_rconConnectService = _rconConnectionInfoService.HasMultipleInformation
? App.GetService<IRconConnection>(typeof(RconMultiConnection))
: App.GetService<IRconConnection>(typeof(RconSingleConnection));
WeakReferenceMessenger.Default.Send(new MainPageLoadValueMessage
{
IsLoaded = true,
});
Log.Information($"[ConnectAsync] 连接服务: {_rconConnectService.GetType().FullName}, 是否为多连接: {IsMultipleConnection}");
_logTextBox = (TextBox)LogicalTreeHelper.FindLogicalNode(_page, "LogText");
LogText += _logService.Log(_languageService.GetKey("text.server.start"));
_logTextBox?.ScrollToEnd();
_rconConnectService.OnConnected += OnConnected;
_rconConnectService.OnMessage += OnMessage;
_rconConnectService.OnClosed += OnClosed;
await Task.Run(_rconConnectService.Connect);
}
catch (AuthenticationException ex)
{
Log.Error($"[ConnectAsync] 认证失败: {ex.Message}");
var msg = ex.Message + _languageService.GetKey("text.server.connect.auth_fail")
.Replace("\\n", "\n");
_messageBoxService.Show(msg, _languageService.GetKey("text.error"), MessageBoxButton.OK,
MessageBoxImage.Error);
LogText += _logService.Log(msg);
// 如果认证失败 就根据当前模式返回对应页面
_navigationService.Navigate(_rconConnectionInfoService.HasMultipleInformation
? typeof(GroupPage)
: typeof(ServersPage));
}
catch (Exception ex)
{
Log.Error($"[ConnectAsync] 连接遇到错误: {ex}");
var msg = _languageService.GetKey("text.server.connect.fail.text")
.Replace("\\n", "\n")
.Replace("%s", ex.Message);
_messageBoxService.Show(msg, _languageService.GetKey("text.error"), MessageBoxButton.OK,
MessageBoxImage.Error);
LogText += _logService.Log(msg);
_logTextBox?.ScrollToEnd();
}
finally
{
_connectingDialogService.Close();
}
// 当只有一个服务器时IsConnected会返回单个客户端的连接状态
// 当有多个服务器时只要有一个客户端在线,IsConnected就会返回True
if (!_rconConnectService.IsConnected() && !RconSettings.IsKeepConnectionWindowOpen)
{
_navigationService.Navigate(2);
}
IsDisconnection = !_rconConnectService.IsConnected();
}
partial void OnIsDisconnectionChanged(bool value)
{
Log.Information("当前客户端状态: {0}", _rconConnectService.IsConnected() ? "在线" : "离线");
}
private void OnConnected(ServerInformation info)
{
Log.Information("[OnConnected] {name}({adapter})", info.Name, string.IsNullOrEmpty(info.Adapter) ? "TCPRcon" : info.Adapter);
LogText += _logService.Log($"$ {info.Name} {_languageService.GetKey("text.server.connected")}");
IsDisconnection = false;
}
[RelayCommand]
private void BackHome()
{
_navigationService.Navigate(_rconConnectionInfoService.HasMultipleInformation
? typeof(GroupPage)
: typeof(ServersPage));
}
[RelayCommand]
private void Exit()
{
WeakReferenceMessenger.Default.Send(new MainPageLoadValueMessage()
{
IsLoaded = false,
});
if (_rconConnectService.IsConnected())
_rconConnectService.Close();
_rconConnectService.OnMessage -= OnMessage;
_rconConnectService.OnClosed -= OnClosed;
_rconConnectService.OnConnected -= OnConnected;
IsDisconnection = false; // 重置状态 此时没有任何连接
}
[RelayCommand]
private void Run()
{
Log.Information("[Run] {0}", CommandText);
if (_rconConnectService.IsConnected())
{
LogText += _logService.Log($"> {CommandText}");
_logTextBox?.ScrollToEnd();
_rconConnectService.Send(CommandText);
CommandText = string.Empty;
}
else
{
IsDisconnection = true;
_rconConnectService.Close();
MessageBox.Show(_languageService.GetKey("text.server.not_connect.text"),
_languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
[RelayCommand]
private void KeyDown(KeyEventArgs e)
{
var textBox = (System.Windows.Controls.TextBox)e.Source;
if (e.Key == Key.Enter)
{
var text = textBox.Text.Trim();
if (string.IsNullOrEmpty(text))
{
return;
}
_commandText = text;
_historyNode = _historyService.InputCmd(_commandText);
Run();
}
else if (e.Key == Key.Up)
{
_historyNode = _historyService.Prev(_historyNode);
textBox.Text = _historyNode?.Cmd;
textBox.Select(textBox.Text?.Length ?? 0, 0);
}
else if (e.Key == Key.Down)
{
_historyNode = _historyService.Next(_historyNode);
textBox.Text = _historyNode?.Cmd;
textBox.Select(textBox.Text?.Length ?? 0, 0);
}
}
}
================================================
FILE: NectarRCON/ViewModels/MainWindowViewModel.cs
================================================
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using Serilog;
using Wpf.Ui.Common;
using Wpf.Ui.Controls;
using Wpf.Ui.Controls.Interfaces;
using Wpf.Ui.Mvvm.Contracts;
using MessageBox = System.Windows.MessageBox;
namespace NectarRCON.ViewModels
{
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<INavigationControl> _navigationItems = new();
private readonly INavigationService _navigationService;
private readonly ILanguageService _languageService;
[ObservableProperty]
private bool _mainPageIsLoaded;
public MainWindowViewModel(INavigationService navigationService, ILanguageService languageService)
{
NavigationItems = new ObservableCollection<INavigationControl>()
{
new NavigationItem
{
Content = "主页",
PageTag = "mainPage",
PageType = typeof(Views.Pages.MainPage)
},
new NavigationItem
{
Content = "设置",
PageTag = "settingsPage",
PageType= typeof(Views.Pages.SettingPage)
},
new NavigationItem
{
Content = "服务器...",
PageTag = "serversPage",
PageType= typeof(Views.Pages.ServersPage)
},
new NavigationItem
{
Content = "关于",
PageTag = "aboutPage",
PageType= typeof(Views.Pages.AboutPage)
},
new NavigationItem
{
Content = "群组",
PageTag = "groupPage",
PageType= typeof(Views.Pages.GroupPage)
},
new NavigationItem
{
Content = "添加服务器",
PageTag = "newGroup",
PageType= typeof(Views.Pages.AddGroupPage)
}
};
_navigationService = navigationService;
_languageService = languageService;
WeakReferenceMessenger.Default.Register<MainPageLoadValueMessage>(this, OnMainPageChange);
}
public void OnMainPageChange(object sender, MainPageLoadValueMessage message)
{
MainPageIsLoaded = message.IsLoaded;
}
[RelayCommand]
private void OnLoad()
{
_navigationService.Navigate(2);
}
[RelayCommand]
private void ClearButtonClick()
{
WeakReferenceMessenger.Default.Send(new ClearLogValueMessage());
}
[RelayCommand]
private void ChangePage(string index)
{
_navigationService.Navigate(int.Parse(index));
}
[RelayCommand]
private void ClearProgramLogs()
{
if (MessageBox.Show(_languageService.GetKey("ui.menu.log.clear_program.ask"), "NectarRcon", MessageBoxButton.YesNo,
MessageBoxImage.Question) != MessageBoxResult.Yes) return;
Log.Information("Clear program logs");
foreach (var logFile in Directory.GetFiles(Path.Combine(Environment.CurrentDirectory, "logs", "program"), "*.log"))
{
try
{
Log.Information("Delete log file: {0}", logFile);
File.Delete(logFile);
}
catch(Exception ex)
{
Log.Error(ex, "Delete log file failed: {0}", logFile);
}
}
}
}
}
================================================
FILE: NectarRCON/ViewModels/ServersPageViewModel.cs
================================================
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using NectarRCON.Windows;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows.Data;
namespace NectarRCON.ViewModels;
public partial class ServersPageViewModel : ObservableObject
{
[ObservableProperty]
private ListCollectionView _serverCollectionView;
[ObservableProperty]
private ObservableCollection<ServerModel> _servers;
private string _filterName = string.Empty;
#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
public ServersPageViewModel()
#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
{
Servers = new();
ServerCollectionView = new(Servers);
ServerCollectionView.Filter += (s) =>
{
if (_filterName == string.Empty)
return true;
if (s is ServerModel model)
{
return model.Name.Contains(_filterName);
}
return false;
};
Refresh();
}
public void Refresh()
{
Servers.Clear();
foreach (ServerInformation information in App.GetService<IServerInformationService>().GetServers())
{
Servers.Add(new ServerModel(information, this));
}
}
[RelayCommand]
public void AddServer()
{
AddServerWindow addServer = App.GetService<AddServerWindow>();
addServer.ShowDialog();
Refresh();
}
[RelayCommand]
public void FilterTextChanged(TextChangedEventArgs e)
{
var box = (System.Windows.Controls.TextBox)e.Source;
_filterName = box.Text.ToString() ?? string.Empty;
_serverCollectionView.Refresh();
}
}
================================================
FILE: NectarRCON/ViewModels/SettingPageViewModel.cs
================================================
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NectarRCON.Core.Helper;
using NectarRCON.Interfaces;
using NectarRCON.Models;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using NectarRCON.Dp;
using Wpf.Ui.Mvvm.Contracts;
namespace NectarRCON.ViewModels;
public partial class SettingPageViewModel : ObservableObject
{
private bool _isLoaded = false;
private readonly ILanguageService _languageService;
private readonly IConfigService _configService;
private readonly IThemeService _themeService;
private readonly RconSettingsDp _rconSettingsDp = DpFile.LoadSingleton<RconSettingsDp>();
[ObservableProperty]
private int _languageSelectedIndex = -1;
[ObservableProperty]
private int _themeSelectedIndex = -1;
[ObservableProperty]
private bool _rconAutoReconnect;
[ObservableProperty]
private bool _isKeepConnectionWindowOpen;
[ObservableProperty]
private ObservableCollection<string> _rconEncoding = [];
[ObservableProperty]
private string _selectedRconEncoding;
[ObservableProperty]
private ObservableCollection<string> _languages = [];
public SettingPageViewModel()
{
_languageService = App.GetService<ILanguageService>();
_configService = App.GetService<IConfigService>();
_themeService = App.GetService<IThemeService>();
RconAutoReconnect = _rconSettingsDp.AutoReconnect;
IsKeepConnectionWindowOpen = _rconSettingsDp.IsKeepConnectionWindowOpen;
RconEncoding.Clear();
foreach (var encoding in Enum.GetNames(typeof(RconEncoding)))
{
RconEncoding.Add(encoding);
}
SelectedRconEncoding = _rconSettingsDp.Encoding.ToString();
}
partial void OnRconAutoReconnectChanged(bool value)
{
_rconSettingsDp.AutoReconnect = value;
_rconSettingsDp.Save();
}
partial void OnIsKeepConnectionWindowOpenChanged(bool value)
{
_rconSettingsDp.IsKeepConnectionWindowOpen = value;
_rconSettingsDp.Save();
}
partial void OnSelectedRconEncodingChanged(string value)
{
_rconSettingsDp.Encoding = Enum.GetValues<RconEncoding>().FirstOrDefault(e => e.ToString() == value);
_rconSettingsDp.Save();
}
[RelayCommand]
public void PageLoad(RoutedEventArgs e)
{
Languages.Clear();
foreach (var language in _languageService.GetLanguages())
{
Languages.Add(language.Value["file.name"].ToString() ?? "NullName");
}
foreach (var language in _languageService.GetLanguages())
{
LanguageSelectedIndex++;
if (language.Key == _configService.GetConfig().LanguageName)
break;
}
ThemeSelectedIndex = (int)_configService.GetConfig().Theme;
_isLoaded = true;
}
[RelayCommand]
public void Exit()
{
_isLoaded = false;
}
[RelayCommand]
public void ThemeSelectionChange()
{
if (!_isLoaded)
return;
_configService.GetConfig().Theme = (ETheme)_themeSelectedIndex;
_configService.Save();
switch ((ETheme)_themeSelectedIndex)
{
case ETheme.System:
_themeService.SetTheme(Win32Helper.GetWindowsTheme() ? Wpf.Ui.Appearance.ThemeType.Dark : Wpf.Ui.Appearance.ThemeType.Light);
break;
case ETheme.Dark:
_themeService.SetTheme(Wpf.Ui.Appearance.ThemeType.Dark);
break;
case ETheme.Light:
_themeService.SetTheme(Wpf.Ui.Appearance.ThemeType.Light);
break;
default:
break;
}
}
[RelayCommand]
public void LanguageSelectionChange(SelectionChangedEventArgs e)
{
if (!_isLoaded)
return;
if (e.AddedItems.Count == 0 || null == e.AddedItems[0])
return;
KeyValuePair<string, ResourceDictionary>? lang = _languageService.GetLanguages().Where(l =>
{
return (l.Value["file.name"].ToString() ?? "NullName") == e.AddedItems[0]!.ToString();
}).FirstOrDefault();
if (null == lang.Value.Value) return;
_configService.GetConfig().LanguageName = lang.Value.Key;
_configService.Save();
_languageService.SelectLanguage(lang.Value.Value["file.name"].ToString() ?? "NullName", true);
}
}
================================================
FILE: NectarRCON/Views/Pages/AboutPage.xaml
================================================
<ui:UiPage
x:Class="NectarRCON.Views.Pages.AboutPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
Title="AboutPage"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<ui:UiPage.DataContext>
<vm:AboutPageViewModel />
</ui:UiPage.DataContext>
<StackPanel VerticalAlignment="Center">
<Border
Width="150"
Height="150"
Margin="0,-50,0,0"
CornerRadius="100">
<Border.Effect>
<DropShadowEffect
BlurRadius="30"
Direction="0"
Opacity="0.4"
ShadowDepth="0"
Color="#202020" />
</Border.Effect>
<Border.Background>
<ImageBrush ImageSource="/Resources/head.png" RenderOptions.BitmapScalingMode="NearestNeighbor" />
</Border.Background>
</Border>
<TextBlock
Margin="0,20,0,0"
HorizontalAlignment="Center"
FontSize="24"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Text="{DynamicResource ui.window.title}" />
<TextBlock
Margin="0,10,0,0"
HorizontalAlignment="Center"
FontSize="18"
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
Text="{DynamicResource app.version}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:Hyperlink
Grid.Column="0"
Margin="5"
HorizontalAlignment="Right"
Content="{DynamicResource ui.about.afdian}"
NavigateUri="https://afdian.net/a/MiuxuE" />
<ui:Hyperlink
Grid.Column="1"
Margin="5"
HorizontalAlignment="Left"
Content="{DynamicResource ui.about.github}"
NavigateUri="https://github.com/zkhssb/NectarRCON" />
</Grid>
</StackPanel>
</ui:UiPage>
================================================
FILE: NectarRCON/Views/Pages/AboutPage.xaml.cs
================================================
namespace NectarRCON.Views.Pages
{
/// <summary>
/// AboutPage.xaml 的交互逻辑
/// </summary>
public partial class AboutPage
{
public AboutPage()
{
InitializeComponent();
}
}
}
================================================
FILE: NectarRCON/Views/Pages/AddGroupPage.xaml
================================================
<ui:UiPage
x:Class="NectarRCON.Views.Pages.AddGroupPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
Title="AddGroupPage"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<ui:UiPage.DataContext>
<vm:AddGroupPageViewModel />
</ui:UiPage.DataContext>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border
Grid.Row="1"
Width="280"
Height="130"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5">
<Border.Background>
<SolidColorBrush Color="{DynamicResource SystemFillColorSolidNeutralBackground}" />
</Border.Background>
<Border.Effect>
<DropShadowEffect
BlurRadius="30"
Direction="0"
Opacity="0.4"
ShadowDepth="0"
Color="#202020" />
</Border.Effect>
<StackPanel
Width="240"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock
Margin="0,0,0,12"
FontSize="16"
Text="{DynamicResource ui.add_group.title}" />
<ui:TextBox PlaceholderText="{DynamicResource ui.add_group.placeholder_text}" Text="{Binding GroupName, UpdateSourceTrigger=PropertyChanged}" />
<Grid Grid.RowSpan="2" Margin="0,10,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:Button
Grid.Column="0"
Margin="0,0,2,0"
HorizontalAlignment="Stretch"
Command="{Binding CancelCommand}"
Content="{DynamicResource text.cancel}" />
<ui:Button
Grid.Column="1"
Margin="2,0,0,0"
HorizontalAlignment="Stretch"
Command="{Binding AddCommand}"
Content="{DynamicResource text.add}" />
</Grid>
</StackPanel>
</Border>
</Grid>
</ui:UiPage>
================================================
FILE: NectarRCON/Views/Pages/AddGroupPage.xaml.cs
================================================
using System;
using Wpf.Ui.Controls;
namespace NectarRCON.Views.Pages
{
/// <summary>
/// AddGroupPage.xaml 的交互逻辑
/// </summary>
public partial class AddGroupPage : UiPage
{
public AddGroupPage()
{
InitializeComponent();
}
}
}
================================================
FILE: NectarRCON/Views/Pages/GroupPage.xaml
================================================
<ui:UiPage
x:Class="NectarRCON.Views.Pages.GroupPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:NectarRCON.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
Title="GroupPage"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<ui:UiPage.DataContext>
<vm:GroupPageViewModel />
</ui:UiPage.DataContext>
<ui:UiPage.Resources>
<c:IntToVisibilityConverter x:Key="IntToVisibilityConverter" />
</ui:UiPage.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
FontSize="16"
Text="{DynamicResource ui.menu.groups}" />
<StackPanel
Grid.Row="1"
Margin="0,-30,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Groups.Count, Converter={StaticResource IntToVisibilityConverter}}">
<TextBlock
HorizontalAlignment="Center"
Focusable="{DynamicResource TextFullColorTertiaryBrush}"
FontSize="18"
Text="{DynamicResource ui.group.no_group_title}" />
<TextBlock
Margin="0,5,0,0"
HorizontalAlignment="Center"
Focusable="{DynamicResource TextFullColorTertiaryBrush}"
FontSize="14"
Text="{DynamicResource ui.group.no_group_subtitle}"
TextWrapping="Wrap" />
<ui:Button
Height="38"
Margin="0,15,0,0"
HorizontalAlignment="Stretch"
Command="{Binding NewGroupCommand}"
Content="{DynamicResource text.add}"
FontSize="16"
Icon="Add24" />
</StackPanel>
<ScrollViewer
Grid.Row="1"
Margin="0,10,-10,10"
VerticalAlignment="Top">
<ItemsControl Margin="0,-10,0,0" ItemsSource="{Binding Groups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ui:CardExpander Margin="0,10,0,0">
<ui:CardExpander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel
Grid.Row="0"
Grid.Column="1"
Margin="0,0,5,0"
Orientation="Horizontal">
<ui:Button
Margin="0,0,5,0"
Command="{Binding AddCommand}"
Content="{DynamicResource text.add}"
Icon="Add24" />
<ui:Button
Margin="0,0,5,0"
Command="{Binding BaseModel.RemoveGroupCommand}"
CommandParameter="{Binding Id}"
Content="{DynamicResource text.delete}"
Icon="Delete24" />
<ui:Button
Margin="0,0,8,0"
Command="{Binding ConnectCommand}"
Content="{DynamicResource text.connect}"
Icon="Connector24" />
</StackPanel>
<TextBlock
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Name}" />
</Grid>
</ui:CardExpander.Header>
<Grid Margin="0,-5,0,0">
<TextBlock
Margin="0,5,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Focusable="{DynamicResource TextFullColorTertiaryBrush}"
FontSize="12"
Text="{DynamicResource ui.group.no_server}"
Visibility="{Binding Servers.Count, Converter={StaticResource IntToVisibilityConverter}}" />
<ItemsControl ItemsSource="{Binding Servers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,5,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
<Button
Grid.Column="1"
Command="{Binding BaseModel.ItemRemoveCommand}"
CommandParameter="{Binding Name}"
Content="{DynamicResource text.remove}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</ui:CardExpander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<ui:Button
Grid.Row="0"
Margin="0,0,4,0"
HorizontalAlignment="Right"
Command="{Binding NewGroupCommand}"
Content="{DynamicResource text.add}"
Icon="Add24"
Visibility="{Binding Groups.Count, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=True}" />
</Grid>
</ui:UiPage>
================================================
FILE: NectarRCON/Views/Pages/GroupPage.xaml.cs
================================================
using System.Windows.Controls;
using Wpf.Ui.Controls;
namespace NectarRCON.Views.Pages
{
/// <summary>
/// GroupPage.xaml 的交互逻辑
/// </summary>
public partial class GroupPage : UiPage
{
public GroupPage()
{
InitializeComponent();
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is ListView listView)
{
listView.SelectedIndex = -1;
}
}
}
}
================================================
FILE: NectarRCON/Views/Pages/MainPage.xaml
================================================
<ui:UiPage x:Class="NectarRCON.Views.Pages.MainPage"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:NectarRCON.Views.Pages"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="MainPage">
<ui:UiPage.DataContext>
<vm:MainPageViewModel/>
</ui:UiPage.DataContext>
<ui:UiPage.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<ControlTemplate x:Key="NoWordSpacingTextBoxTemplate" TargetType="{x:Type TextBox}">
<Grid>
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Auto"
VerticalContentAlignment="Top"
IsTabStop="False">
<Grid Background="{TemplateBinding Background}"
Margin="{TemplateBinding Padding}">
<TextBlock Text="{TemplateBinding Text}"
FontFamily="{TemplateBinding FontFamily}"
TextWrapping="Wrap"
VerticalAlignment="Top"
Margin="0,0,0,2" />
</Grid>
</ScrollViewer>
</Grid>
</ControlTemplate>
</ui:UiPage.Resources>
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Loaded">
<i:InvokeCommandAction
PassEventArgsToCommand="True"
Command="{Binding LoadCommand}"/>
</i:EventTrigger>
<i:EventTrigger
EventName="Unloaded">
<i:InvokeCommandAction Command="{Binding ExitCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ui:TextBox
ClearButtonEnabled="False"
Name="LogText"
FontFamily="Consolas"
BorderThickness="0"
Margin="5"
Grid.Row="0"
TextWrapping="Wrap"
TextAlignment="Left"
AcceptsReturn="True"
VerticalScrollBarVisibility="Visible"
VerticalContentAlignment="Top"
VerticalAlignment="Stretch"
IsReadOnly="True"
Text="{Binding LogText}"
/>
<Grid
Margin="5"
Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ui:TextBox
Text="{Binding CommandText}"
Grid.Column="0"
BorderThickness="0"
PlaceholderText="/">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="PreviewKeyDown">
<i:InvokeCommandAction
PassEventArgsToCommand="True"
Command="{Binding KeyDownCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:TextBox>
<Button
Grid.Column="1"
Margin="10,0,0,0"
Width="120"
Content="{DynamicResource ui.main_page.run}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Click">
<i:InvokeCommandAction Command="{Binding RunCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
<Grid
Visibility="{Binding IsDisconnection, Converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Row="0"
Grid.RowSpan="2">
<Grid.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#CF202020" />
<GradientStop Offset="1.0" Color="#8F202020" />
</LinearGradientBrush>
</Grid.Background>
<Border
CornerRadius="5"
Height="150"
Width="200">
<Border.Background>
<SolidColorBrush Color="{DynamicResource SystemFillColorSolidNeutralBackground}"/>
</Border.Background>
<Border.Effect>
<DropShadowEffect
BlurRadius="30"
Direction="0"
Opacity="0.4"
ShadowDepth="0"
Color="#202020" />
</Border.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0">
<TextBlock
HorizontalAlignment="Center"
FontSize="16"
Text="{DynamicResource ui.main_page.offline.single}"/>
<TextBlock
Margin="0,10,0,0"
FontSize="14"
HorizontalAlignment="Center"
Visibility="{Binding IsMultipleConnection, Converter={StaticResource BooleanToVisibilityConverter}}"
Text="{DynamicResource ui.main_page.offline.multiple}"/>
</StackPanel>
<UniformGrid Margin="0,0,0,10" Grid.Row="1" HorizontalAlignment="Center" Columns="2">
<Button Margin="2" HorizontalAlignment="Center" Command="{Binding BackHomeCommand}" Content="{DynamicResource ui.main_page.back_home}"/>
<Button Margin="2" HorizontalAlignment="Center" Command="{Binding ReConnectCommand}" Content="{DynamicResource ui.main_page.re_connect}"/>
</UniformGrid>
</Grid>
</Border>
</Grid>
</Grid>
</ui:UiPage>
================================================
FILE: NectarRCON/Views/Pages/MainPage.xaml.cs
================================================
namespace NectarRCON.Views.Pages
{
/// <summary>
/// MainPage.xaml 的交互逻辑
/// </summary>
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
}
}
}
================================================
FILE: NectarRCON/Views/Pages/ServersPage.xaml
================================================
<ui:UiPage
x:Class="NectarRCON.Views.Pages.ServersPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
Title="ServersPage"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<ui:UiPage.DataContext>
<vm:ServersPageViewModel />
</ui:UiPage.DataContext>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
FontSize="16"
Text="{DynamicResource ui.server_page.text}" />
<ScrollViewer Grid.Row="1" Margin="0,10,-10,10">
<ItemsControl ItemsSource="{Binding ServerCollectionView}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
Margin="-5"
VerticalAlignment="Top"
Columns="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ui:CardAction
Margin="5"
Command="{Binding ConnectCommand}"
Focusable="False">
<ui:CardAction.ContextMenu>
<ContextMenu>
<ui:MenuItem
Command="{Binding ConnectCommand}"
Header="{DynamicResource ui.server_page.menu.open}"
SymbolIcon="Open24" />
<ui:MenuItem
Command="{Binding EditCommand}"
Header="{DynamicResource ui.server_page.menu.edit}"
SymbolIcon="Edit24" />
<ui:MenuItem
Command="{Binding EditPasswordCommand}"
Header="{DynamicResource ui.server_page.menu.edit_password}"
SymbolIcon="Password24" />
<ui:MenuItem
Command="{Binding DeleteCommand}"
Header="{DynamicResource ui.server_page.menu.delete}"
SymbolIcon="Delete24" />
</ContextMenu>
</ui:CardAction.ContextMenu>
<StackPanel>
<TextBlock
Name="Name"
FontSize="16"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Text="{Binding Name}" />
<TextBlock
Margin="0,10,0,0"
FontSize="14"
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
Text="{Binding Address}" />
</StackPanel>
</ui:CardAction>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<ui:TextBox
Grid.Row="2"
Margin="0,0,130,0"
PlaceholderText="{DynamicResource ui.server_page.search}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding FilterTextChangedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:TextBox>
<ui:Button
Grid.Row="2"
Margin="0,0,4,0"
HorizontalAlignment="Right"
Command="{Binding AddServerCommand}"
Content="{DynamicResource ui.server_page.add}"
Icon="Add24" />
</Grid>
</ui:UiPage>
================================================
FILE: NectarRCON/Views/Pages/ServersPage.xaml.cs
================================================
namespace NectarRCON.Views.Pages
{
/// <summary>
/// ServersPage.xaml 的交互逻辑
/// </summary>
public partial class ServersPage
{
public ServersPage()
{
InitializeComponent();
}
}
}
================================================
FILE: NectarRCON/Views/Pages/SettingPage.xaml
================================================
<ui:UiPage x:Class="NectarRCON.Views.Pages.SettingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:NectarRCON.Views.Pages"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="SettingPage">
<ui:UiPage.DataContext>
<vm:SettingPageViewModel/>
</ui:UiPage.DataContext>
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Loaded">
<i:InvokeCommandAction
PassEventArgsToCommand="True"
Command="{Binding PageLoadCommand}"/>
</i:EventTrigger>
<i:EventTrigger
EventName="Unloaded">
<i:InvokeCommandAction
Command="{Binding ExitCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<StackPanel
Margin="10,10,10,0">
<TextBlock
FontSize="16"
Margin="0,0,5,0"
VerticalAlignment="Center"
Text="{DynamicResource ui.settings.ui}"/>
<TextBlock
FontSize="14"
Margin="0,10,5,0"
VerticalAlignment="Center"
Text="{DynamicResource ui.settings.language}"/>
<ComboBox
x:Name="LanguageComboBox"
ItemsSource="{Binding Languages, Mode=OneWay}"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch"
SelectedIndex="{Binding LanguageSelectedIndex,Mode=TwoWay}"
Focusable="False">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="SelectionChanged">
<i:InvokeCommandAction
PassEventArgsToCommand="True"
Command="{Binding LanguageSelectionChangeCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<TextBlock
FontSize="14"
Margin="0,10,5,0"
VerticalAlignment="Center"
Text="{DynamicResource ui.settings.theme}"/>
<ComboBox
x:Name="ThemeComboBox"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch"
SelectedIndex="{Binding ThemeSelectedIndex}"
Focusable="False">
<ComboBoxItem Content="{DynamicResource ui.settings.theme.auto}"/>
<ComboBoxItem Content="{DynamicResource ui.settings.theme.dark}"/>
<ComboBoxItem Content="{DynamicResource ui.settings.theme.light}"/>
<i:Interaction.Triggers>
<i:EventTrigger
EventName="SelectionChanged">
<i:InvokeCommandAction
Command="{Binding ThemeSelectionChangeCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<TextBlock
FontSize="16"
Margin="0,10,5,0"
VerticalAlignment="Center"
Text="{DynamicResource ui.settings.rcon}"/>
<ui:ToggleSwitch
FontSize="14"
Margin="0,10,5,0"
IsChecked="{Binding RconAutoReconnect}"
Content="{DynamicResource ui.settings.rcon.auto_reconnect}"/>
<ui:ToggleSwitch
FontSize="14"
Margin="0,10,5,0"
IsChecked="{Binding IsKeepConnectionWindowOpen}"
Content="{DynamicResource ui.settings.rcon.is_keep_connection_window_open}"/>
<TextBlock
FontSize="14"
Margin="0,10,5,0"
Text="{DynamicResource ui.settings.rcon.encoding}"/>
<ComboBox Margin="0,5,0,0" ItemsSource="{Binding RconEncoding}" SelectedItem="{Binding SelectedRconEncoding}"/>
<!--
<TextBlock
FontSize="16"
Margin="0,10,5,0"
VerticalAlignment="Center"
Text="{DynamicResource ui.settings.command_record_limit}"/>
<ui:NumberBox
IntegersOnly="True"
HorizontalAlignment="Stretch"
Max="9999"
Min="10" Step="1"/>
<Button
HorizontalAlignment="Stretch"
Margin="0,20,0,0"
Content="{DynamicResource ui.settings.rcon_account}"/>
-->
</StackPanel>
</ui:UiPage>
================================================
FILE: NectarRCON/Views/Pages/SettingPage.xaml.cs
================================================
namespace NectarRCON.Views.Pages;
public partial class SettingPage
{
public SettingPage()
{
InitializeComponent();
}
}
================================================
FILE: NectarRCON/Windows/AddServerWindow.xaml
================================================
<ui:UiWindow x:Class="NectarRCON.Windows.AddServerWindow"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON.Windows"
mc:Ignorable="d"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen"
Title="{DynamicResource ui.add_server_window.title}"
ResizeMode="NoResize"
Height="290"
MinHeight="290"
MaxHeight="290"
Width="380"
MinWidth="380"
MaxWidth="380">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ui:TitleBar
Icon="pack://application:,,,/Resources/Icon.png"
FontSize="14"
ShowMaximize="False"
ShowMinimize="False"
Title="{DynamicResource ui.add_server_window.title}" Grid.ColumnSpan="2" VerticalAlignment="Center"/>
<StackPanel
Margin="10,-5,10,10"
Grid.Row="1" Grid.ColumnSpan="2">
<TextBlock
Margin="0,10,0,2"
Text="{DynamicResource ui.add_server_window.name}"/>
<ui:TextBox
Text="{Binding ViewModel.ServerName,Mode=TwoWay}"/>
<TextBlock
Margin="0,10,0,2"
Text="{DynamicResource ui.add_server_window.address}"/>
<ui:TextBox
Text="{Binding ViewModel.ServerAddress,Mode=TwoWay}"/>
<TextBlock
Margin="0,10,0,2"
Text="{DynamicResource ui.add_server_window.port}"/>
<ui:NumberBox
Text="{Binding ViewModel.ServerPort,Mode=TwoWay}"
Min="0"
Max="65535"
IntegersOnly="True" Cursor="IBeam"/>
</StackPanel>
<Grid
Grid.Row="2"
Margin="10,0,10,10" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<ui:Button
Margin="0,0,2,0"
HorizontalAlignment="Stretch"
Grid.Column="0"
Appearance="Transparent"
Click="CancelButtonClick"
Content="{DynamicResource ui.add_server_window.cancel}"/>
<ui:Button
Margin="2,0,0,0"
HorizontalAlignment="Stretch"
Grid.Column="1"
Appearance="Secondary"
Content="{DynamicResource ui.add_server_window.add}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Click">
<i:InvokeCommandAction
Command="{Binding ViewModel.OkCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:Button>
</Grid>
</Grid>
</ui:UiWindow>
================================================
FILE: NectarRCON/Windows/AddServerWindow.xaml.cs
================================================
using NectarRCON.ViewModels;
using System.Windows;
namespace NectarRCON.Windows
{
/// <summary>
/// AddServerWindow.xaml 的交互逻辑
/// </summary>
public partial class AddServerWindow
{
public AddServerWindowViewModel ViewModel
{
get;
}
public AddServerWindow(AddServerWindowViewModel viewModel)
{
ViewModel = viewModel;
viewModel.SetWindow(this);
InitializeComponent();
DataContext = this;
}
private void CancelButtonClick(object sender, RoutedEventArgs e)
=> Close();
}
}
================================================
FILE: NectarRCON/Windows/EditPasswordWindow.xaml
================================================
<ui:UiWindow x:Class="NectarRCON.Windows.EditPasswordWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:NectarRCON.Windows"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
mc:Ignorable="d"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen"
Title="{DynamicResource ui.edit_password.title}"
ResizeMode="NoResize"
Width="380"
MinWidth="380"
MaxWidth="380"
Height="170"
MinHeight="170"
MaxHeight="170">
<Window.DataContext>
<vm:EditPasswordWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ui:TitleBar
Icon="pack://application:,,,/Resources/Icon.png"
FontSize="14"
ShowMaximize="False"
ShowMinimize="False"
ShowClose="False"
Title="{DynamicResource ui.edit_password.title}" Grid.ColumnSpan="2" VerticalAlignment="Center"/>
<StackPanel
Margin="10,-5,10,10"
Grid.Row="1" Grid.ColumnSpan="2">
<TextBlock
Margin="0,10,0,2"
Text="{DynamicResource ui.edit_password.text}"/>
<ui:PasswordBox
Password="{Binding Password,Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="PasswordChanged">
<i:InvokeCommandAction Command="{Binding TextChangeCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:PasswordBox>
</StackPanel>
<Grid
Grid.Row="2"
Margin="10,0,10,10" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox
Grid.Column="0"
IsEnabled="False"
IsChecked="{Binding Path=IsEmpty,Mode=TwoWay}"
Content="{DynamicResource ui.edit_password.is_empty}"/>
<ui:Button
Margin="2,0,0,0"
HorizontalAlignment="Stretch"
Grid.Column="1"
Appearance="Secondary"
Content="{DynamicResource text.ok}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Click">
<i:InvokeCommandAction Command="{Binding SetPasswordCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:Button>
</Grid>
</Grid>
</ui:UiWindow>
================================================
FILE: NectarRCON/Windows/EditPasswordWindow.xaml.cs
================================================
using NectarRCON.ViewModels;
using System.Windows;
namespace NectarRCON.Windows
{
/// <summary>
/// EditPasswordWindow.xaml 的交互逻辑
/// </summary>
public partial class EditPasswordWindow
{
public EditPasswordWindow()
{
InitializeComponent();
((EditPasswordWindowViewModel)this.DataContext).SetWindow(this);
}
private void CancelButtonClick(object sender, RoutedEventArgs e)
=> Close();
}
}
================================================
FILE: NectarRCON/Windows/EditServerWindow.xaml
================================================
<ui:UiWindow x:Class="NectarRCON.Windows.EditServerWindow"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON.Windows"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
mc:Ignorable="d"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen"
Title="{DynamicResource ui.edit_server_window.title}"
ResizeMode="NoResize"
Height="290"
MinHeight="290"
MaxHeight="290"
Width="380"
MinWidth="380"
MaxWidth="380">
<ui:UiWindow.DataContext>
<vm:EditServerWindowViewModel/>
</ui:UiWindow.DataContext>
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Loaded">
<i:InvokeCommandAction
PassEventArgsToCommand="True"
Command="{Binding LoadCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ui:TitleBar
Icon="pack://application:,,,/Resources/Icon.png"
FontSize="14"
ShowMaximize="False"
ShowMinimize="False"
Title="{DynamicResource ui.edit_server_window.title}" Grid.ColumnSpan="2" VerticalAlignment="Center"/>
<StackPanel
Margin="10,-5,10,10"
Grid.Row="1" Grid.ColumnSpan="2">
<TextBlock
Margin="0,10,0,2"
Text="{DynamicResource ui.add_server_window.name}"/>
<ui:TextBox
IsEnabled="False"
Text="{Binding SelectServer.Name,Mode=OneWay}"/>
<TextBlock
Margin="0,10,0,2"
Text="{DynamicResource ui.add_server_window.address}"/>
<ui:TextBox
Text="{Binding Address,Mode=TwoWay}"/>
<TextBlock
Margin="0,10,0,2"
Text="{DynamicResource ui.add_server_window.port}"/>
<ui:NumberBox
Text="{Binding Port,Mode=TwoWay}"
Min="0"
Max="65535"
IntegersOnly="True" Cursor="IBeam"/>
</StackPanel>
<Grid
Grid.Row="2"
Margin="10,0,10,10" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<ui:Button
Margin="0,0,2,0"
HorizontalAlignment="Stretch"
Grid.Column="0"
Appearance="Transparent"
Content="{DynamicResource text.cancel}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Click">
<i:InvokeCommandAction
Command="{Binding ExitCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:Button>
<ui:Button
Margin="2,0,0,0"
HorizontalAlignment="Stretch"
Grid.Column="1"
Appearance="Secondary"
Content="{DynamicResource text.ok}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Click">
<i:InvokeCommandAction
Command="{Binding OkCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:Button>
</Grid>
</Grid>
</ui:UiWindow>
================================================
FILE: NectarRCON/Windows/EditServerWindow.xaml.cs
================================================
namespace NectarRCON.Windows
{
/// <summary>
/// EditServerWindow.xaml 的交互逻辑
/// </summary>
public partial class EditServerWindow
{
public EditServerWindow()
{
InitializeComponent();
}
}
}
================================================
FILE: NectarRCON/Windows/JoinGroupWindow.xaml
================================================
<ui:UiWindow
x:Class="NectarRCON.Windows.JoinGroupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:NectarRCON.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON.Windows"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vm="clr-namespace:NectarRCON.ViewModels"
Title="{DynamicResource ui.join_group.title}"
Width="460"
Height="580"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<ui:UiWindow.DataContext>
<vm:JoinGroupWindowViewModel />
</ui:UiWindow.DataContext>
<ui:UiWindow.Resources>
<c:IntToVisibilityConverter x:Key="IntToVisibilityConverter" />
</ui:UiWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ui:TitleBar
Title="{DynamicResource ui.join_group.title}"
FontSize="14"
Icon="pack://application:,,,/Resources/Icon.png"
ShowMaximize="False"
ShowMinimize="False" />
<StackPanel
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding ServerCollectionView.Count, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=False}">
<TextBlock Text="{DynamicResource ui.join_group.no_server}" />
<Button
x:Name="CloseButton"
Margin="0,15,0,0"
HorizontalAlignment="Stretch"
Click="CloseButton_Click"
Content="{DynamicResource text.cancel}" />
</StackPanel>
<ListView
x:Name="ServersListView"
Grid.Row="1"
ItemsSource="{Binding ServerCollectionView}"
SelectionChanged="ServersListView_SelectionChanged"
Visibility="{Binding ServerCollectionView.Count, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=True}">
<ListView.ItemTemplate>
<DataTemplate>
<ui:Card>
<TextBlock Text="{Binding}" />
</ui:Card>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ui:UiWindow>
================================================
FILE: NectarRCON/Windows/JoinGroupWindow.xaml.cs
================================================
using NectarRCON.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Wpf.Ui.Controls;
namespace NectarRCON.Windows
{
/// <summary>
/// JoinGroupWindow.xaml 的交互逻辑
/// </summary>
public partial class JoinGroupWindow : UiWindow
{
public string? SelectedServer = null;
public JoinGroupWindow()
{
InitializeComponent();
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
public void AddBlackList(string value)
{
((JoinGroupWindowViewModel)DataContext).BlackList?.Add(value);
((JoinGroupWindowViewModel)DataContext).ServerCollectionView?.Refresh();
}
private void ServersListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(e.AddedItems.Count > 0)
{
SelectedServer = e.AddedItems[0]?.ToString();
Close();
}
}
}
}
================================================
FILE: NectarRCON/Windows/MainWindow.xaml
================================================
<ui:UiWindow x:Class="NectarRCON.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:NectarRCON"
mc:Ignorable="d"
Title="{DynamicResource ui.window.title}"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen"
MinHeight="690"
MinWidth="650"
Height="690"
Width="650">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding ViewModel.LoadCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ui:TitleBar
Icon="pack://application:,,,/Resources/Icon.png"
FontSize="14"
Title="{DynamicResource ui.window.title}"
Grid.Row="0" />
<Menu
Grid.Row="1"
Focusable="False">
<MenuItem
Focusable="False"
Header="{DynamicResource ui.menu.server}">
<MenuItem
Focusable="False"
Header="{DynamicResource ui.menu.server_list}"
CommandParameter="2"
Command="{Binding ViewModel.ChangePageCommand}" />
<MenuItem
Focusable="False"
Header="{DynamicResource ui.menu.groups}"
CommandParameter="4"
Command="{Binding ViewModel.ChangePageCommand}" />
</MenuItem>
<MenuItem
IsEnabled="{Binding ViewModel.MainPageIsLoaded}"
Focusable="False"
Header="{DynamicResource ui.menu.log}">
<MenuItem
Width="120"
Command="{Binding ViewModel.ClearButtonClickCommand}"
Header="{DynamicResource ui.menu.log.clear}" />
</MenuItem>
<MenuItem
Focusable="False"
Header="{DynamicResource ui.menu.program}">
<MenuItem
Width="120"
Header="{DynamicResource ui.menu.program.settings}"
CommandParameter="1"
Command="{Binding ViewModel.ChangePageCommand}"/>
<MenuItem
Width="120"
Header="{DynamicResource ui.menu.program.about}"
CommandParameter="3"
Command="{Binding ViewModel.ChangePageCommand}"/>
<MenuItem
Width="120"
IsEnabled="False"
Header="{DynamicResource ui.menu.program.check_update}" />
<MenuItem
Width="120"
Header="{DynamicResource ui.menu.log.clear_program}"
Command="{Binding ViewModel.ClearProgramLogsCommand}"/>
</MenuItem>
</Menu>
<ui:NavigationCompact
Visibility="Hidden"
Height="1"
Width="1"
x:Name="RootNavigation"
Items="{Binding ViewModel.NavigationItems, Mode=TwoWay}"
Frame="{Binding ElementName=MainFrame,Mode=OneWay}" />
<Frame
x:Name="MainFrame"
Grid.Row="2" />
<Grid
Visibility="Hidden"
Grid.Row="1"
Gr
gitextract_0vsxp36e/ ├── .gitattributes ├── .github/ │ └── workflows/ │ └── dotnet-desktop.yml ├── .gitignore ├── LICENSE.txt ├── NectarRCON/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── AssemblyInfo.cs │ ├── Converters/ │ │ ├── BoolToVisibilityConverter.cs │ │ └── IntToVisibilityConverter.cs │ ├── Dp/ │ │ ├── DpFile.cs │ │ └── RconSettingsDp.cs │ ├── Entity/ │ │ ├── ClearLogValueMessage.cs │ │ ├── Config.cs │ │ ├── ETheme.cs │ │ ├── Group.cs │ │ ├── MainPageLoadValueMessage.cs │ │ ├── ServerInformation.cs │ │ └── ServerPassword.cs │ ├── Interfaces/ │ │ ├── IConfigService.cs │ │ ├── IConnectingDialogService.cs │ │ ├── IGroupService.cs │ │ ├── IHistoryService.cs │ │ ├── ILanguageService.cs │ │ ├── ILogService.cs │ │ ├── IMessageBoxService.cs │ │ ├── IRconConnectionInfoService.cs │ │ ├── IServerInformationService.cs │ │ └── IServerPasswordService.cs │ ├── Models/ │ │ ├── GroupModel.cs │ │ ├── GroupServerItemModel.cs │ │ └── ServerModel.cs │ ├── NectarRCON.csproj │ ├── Rcon/ │ │ ├── IRconConnection.cs │ │ ├── RconMultiConnection.cs │ │ └── RconSingleConnection.cs │ ├── Resources/ │ │ └── Languages/ │ │ ├── en_us.xaml │ │ ├── zh_cn.xaml │ │ └── zh_tw.xaml │ ├── Services/ │ │ ├── ApplicationHostService.cs │ │ ├── ConfigService.cs │ │ ├── ConnectingDialogService.cs │ │ ├── GroupService.cs │ │ ├── HistoryService.cs │ │ ├── LanguageService.cs │ │ ├── LogService.cs │ │ ├── MessageBoxService.cs │ │ ├── RconConnectionInfoService.cs │ │ ├── ServerInformationService.cs │ │ └── ServerPasswordService.cs │ ├── ViewModels/ │ │ ├── AboutPageViewModel.cs │ │ ├── AddGroupPageViewModel.cs │ │ ├── AddServerWindowViewModel.cs │ │ ├── EditPasswordWindowViewModel.cs │ │ ├── EditServerWindowViewModel.cs │ │ ├── GroupPageViewModel.cs │ │ ├── JoinGroupWindowViewModel.cs │ │ ├── MainPageViewModel.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ServersPageViewModel.cs │ │ └── SettingPageViewModel.cs │ ├── Views/ │ │ └── Pages/ │ │ ├── AboutPage.xaml │ │ ├── AboutPage.xaml.cs │ │ ├── AddGroupPage.xaml │ │ ├── AddGroupPage.xaml.cs │ │ ├── GroupPage.xaml │ │ ├── GroupPage.xaml.cs │ │ ├── MainPage.xaml │ │ ├── MainPage.xaml.cs │ │ ├── ServersPage.xaml │ │ ├── ServersPage.xaml.cs │ │ ├── SettingPage.xaml │ │ └── SettingPage.xaml.cs │ ├── Windows/ │ │ ├── AddServerWindow.xaml │ │ ├── AddServerWindow.xaml.cs │ │ ├── EditPasswordWindow.xaml │ │ ├── EditPasswordWindow.xaml.cs │ │ ├── EditServerWindow.xaml │ │ ├── EditServerWindow.xaml.cs │ │ ├── JoinGroupWindow.xaml │ │ ├── JoinGroupWindow.xaml.cs │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ └── app.manifest ├── NectarRCON.Adapter.Minecraft/ │ ├── MinecraftRconClient.cs │ ├── NectarRCON.Adapter.Minecraft.csproj │ ├── Packet.cs │ ├── PacketEncoder.cs │ └── README.md ├── NectarRCON.Core/ │ ├── Helper/ │ │ ├── AdapterHelpers.cs │ │ ├── DNSHelpers.cs │ │ └── Win32Helper.cs │ └── NectarRCON.Core.csproj ├── NectarRCON.Export/ │ ├── Client/ │ │ └── BaseTcpClient.cs │ ├── Interfaces/ │ │ ├── IRconAdapter.cs │ │ └── IRconClient.cs │ └── NectarRCON.Export.csproj ├── NectarRCON.Tests/ │ ├── Adapter/ │ │ └── MinecraftRconTest.cs │ ├── DNSHelperTests.cs │ ├── GroupServiceTests.cs │ ├── MessageBoxServiceTests.cs │ ├── NectarRCON.Tests.csproj │ ├── UpdaterTests.cs │ └── Usings.cs ├── NectarRCON.Updater/ │ ├── AppVersion.cs │ ├── GithubUpdater.cs │ ├── IUpdater.cs │ ├── Model/ │ │ ├── Asset.cs │ │ └── Release.cs │ └── NectarRCON.Updater.csproj ├── NectarRCON.sln ├── README.md └── README_EN.md
SYMBOL INDEX (392 symbols across 80 files)
FILE: NectarRCON.Adapter.Minecraft/MinecraftRconClient.cs
class MinecraftRconClient (line 8) | [Description("rcon.minecraft")]
method Disconnect (line 23) | public void Disconnect()
method Dispose (line 36) | public override void Dispose()
method Read (line 43) | public override byte[] Read(StreamReader reader)
method Run (line 51) | public string Run(string command)
method GetEncoding (line 65) | public Encoding GetEncoding()
method SetEncoding (line 68) | public void SetEncoding(Encoding encoding)
method Connect (line 73) | public bool Connect(string address, int port)
method Authenticate (line 87) | public bool Authenticate(string password)
method Send (line 101) | private Packet Send(Packet packet)
FILE: NectarRCON.Adapter.Minecraft/Packet.cs
class Packet (line 4) | public class Packet
method Packet (line 11) | public Packet(int length, int id, PacketType type, string body)
method Packet (line 19) | public Packet(PacketType type, string body)
method SetId (line 25) | public void SetId(int id)
method Encode (line 30) | public byte[] Encode(Encoding? encoding = null)
FILE: NectarRCON.Adapter.Minecraft/PacketEncoder.cs
type PacketType (line 5) | public enum PacketType : int
class PacketEncoder (line 13) | public abstract class PacketEncoder
method Encode (line 17) | public static byte[] Encode(Packet msg, Encoding? encoding = null)
method Decode (line 30) | public static Packet Decode(byte[] bytes, Encoding? encoding = null)
FILE: NectarRCON.Core/Helper/AdapterHelpers.cs
class AdapterHelpers (line 5) | public static class AdapterHelpers
method CreateAdapterInstance (line 7) | public static IRconAdapter? CreateAdapterInstance(string adapter)
FILE: NectarRCON.Core/Helper/DNSHelpers.cs
class DNSHelpers (line 5) | public class DNSHelpers
method AQuery (line 7) | public static string AQuery(string host)
method SRVQuery (line 19) | public static string SRVQuery(string host)
FILE: NectarRCON.Core/Helper/Win32Helper.cs
class Win32Helper (line 2) | public static class Win32Helper
method GetWindowsTheme (line 4) | public static bool GetWindowsTheme()
FILE: NectarRCON.Export/Client/BaseTcpClient.cs
class BaseTcpClient (line 9) | public abstract class BaseTcpClient : IRconClient
method Dispose (line 19) | public virtual void Dispose()
method Send (line 24) | public byte[] Send(byte[] bytes)
method Read (line 35) | public abstract byte[] Read(StreamReader reader);
method Start (line 37) | public void Start(string address, int port)
method Stop (line 57) | public void Stop()
FILE: NectarRCON.Export/Interfaces/IRconAdapter.cs
type IRconAdapter (line 7) | public interface IRconAdapter : IDisposable
method Connect (line 17) | bool Connect(string address, int port);
method Authenticate (line 23) | bool Authenticate(string password);
method Disconnect (line 28) | void Disconnect();
method Run (line 34) | string Run(string command);
method GetEncoding (line 36) | Encoding GetEncoding();
method SetEncoding (line 37) | void SetEncoding(Encoding encoding);
FILE: NectarRCON.Export/Interfaces/IRconClient.cs
type IRconClient (line 5) | public interface IRconClient : IDisposable
method Start (line 18) | void Start(string address, int port);
method Stop (line 22) | void Stop();
method Send (line 28) | byte[] Send(byte[] bytes);
FILE: NectarRCON.Tests/Adapter/MinecraftRconTest.cs
class MinecraftRconTest (line 6) | [TestClass]
method connectAndAuthenticate (line 16) | private void connectAndAuthenticate()
method Connect (line 26) | public void Connect()
method Authenticate (line 33) | public void Authenticate()
method Run (line 40) | public void Run()
FILE: NectarRCON.Tests/DNSHelperTests.cs
class DNSHelperTests (line 4) | [TestClass]
method ATest (line 10) | [TestMethod]
method SRVTest (line 21) | [TestMethod]
FILE: NectarRCON.Tests/GroupServiceTests.cs
class GroupServiceTests (line 8) | [TestClass]
class MyLanguageService (line 11) | private class MyLanguageService : ILanguageService
method GetKey (line 13) | public string GetKey(string key)
method GetLanguages (line 18) | public Dictionary<string, ResourceDictionary> GetLanguages()
method GetSelectedLanguage (line 23) | public ResourceDictionary GetSelectedLanguage()
method Refresh (line 28) | public void Refresh()
method SelectLanguage (line 33) | public void SelectLanguage()
method SelectLanguage (line 38) | public void SelectLanguage(string languageName, bool name)
method Dump (line 45) | [TestMethod]
method TestAll (line 51) | [TestMethod]
FILE: NectarRCON.Tests/MessageBoxServiceTests.cs
class MessageBoxServiceTests (line 7) | [TestClass]
class MyLanguageService (line 10) | private class MyLanguageService : ILanguageService
method GetKey (line 12) | public string GetKey(string key)
method GetLanguages (line 17) | public Dictionary<string, ResourceDictionary> GetLanguages()
method GetSelectedLanguage (line 22) | public ResourceDictionary GetSelectedLanguage()
method Refresh (line 27) | public void Refresh()
method SelectLanguage (line 32) | public void SelectLanguage()
method SelectLanguage (line 37) | public void SelectLanguage(string languageName, bool name)
method ExceptionTest (line 44) | [TestMethod]
FILE: NectarRCON.Tests/UpdaterTests.cs
class UpdaterTests (line 10) | [TestClass]
method Github (line 13) | [TestMethod]
method AppVersionTest (line 21) | [TestMethod]
FILE: NectarRCON.Updater/AppVersion.cs
class AppVersion (line 6) | public class AppVersion
method ToString (line 19) | public override string ToString()
method Equals (line 24) | public override bool Equals(object? obj)
method AppVersion (line 49) | private AppVersion() { }
method ParseVersion (line 51) | public static AppVersion ParseVersion(string version)
method GetHashCode (line 100) | public override int GetHashCode()
FILE: NectarRCON.Updater/GithubUpdater.cs
class GithubUpdater (line 11) | public class GithubUpdater : IUpdater
method GetLatestVersion (line 24) | private AppVersion? GetLatestVersion(bool enablePre)
method IsLatestVersion (line 65) | public bool IsLatestVersion()
method Setup (line 71) | public void Setup()
method SetVersion (line 76) | public void SetVersion(string version)
method SetPreEnable (line 81) | public void SetPreEnable(bool value)
method GetLatestVersion (line 86) | public AppVersion GetLatestVersion()
FILE: NectarRCON.Updater/IUpdater.cs
type IUpdater (line 3) | public interface IUpdater
method SetVersion (line 8) | void SetVersion(string version);
method IsLatestVersion (line 12) | bool IsLatestVersion();
method GetLatestVersion (line 16) | AppVersion GetLatestVersion();
method Setup (line 20) | void Setup();
method SetPreEnable (line 24) | void SetPreEnable(bool value);
FILE: NectarRCON.Updater/Model/Asset.cs
class Asset (line 5) | public class Asset
FILE: NectarRCON.Updater/Model/Release.cs
class Release (line 10) | public class Release
FILE: NectarRCON/App.xaml.cs
class App (line 24) | public partial class App
method GetService (line 77) | public static T GetService<T>()
method GetService (line 83) | public static T GetService<T>(Type type)
method OnStartup (line 89) | private async void OnStartup(object sender, StartupEventArgs e)
method CurrentDomain_UnhandledException (line 102) | private static void CurrentDomain_UnhandledException(object sender, Un...
method OnExit (line 114) | private async void OnExit(object sender, ExitEventArgs e)
FILE: NectarRCON/Converters/BoolToVisibilityConverter.cs
class BoolToVisibilityConverter (line 8) | public class BoolToVisibilityConverter : IValueConverter
method Convert (line 10) | public object? Convert(object value, Type targetType, object parameter...
method ConvertBack (line 19) | public object ConvertBack(object value, Type targetType, object parame...
FILE: NectarRCON/Converters/IntToVisibilityConverter.cs
class IntToVisibilityConverter (line 8) | public class IntToVisibilityConverter : IValueConverter
method Convert (line 10) | public object? Convert(object value, Type targetType, object parameter...
method ConvertBack (line 29) | public object ConvertBack(object value, Type targetType, object parame...
FILE: NectarRCON/Dp/DpFile.cs
class DpFile (line 11) | public abstract class DpFile
method Save (line 31) | public void Save()
method Load (line 46) | private static T? Load<T>(string name, string? basePath = null)
method LoadSingleton (line 60) | public static T LoadSingleton<T>()
FILE: NectarRCON/Dp/RconSettingsDp.cs
type RconEncoding (line 6) | public enum RconEncoding
class RconEncodingExtensions (line 19) | public static class RconEncodingExtensions
method GetEncoding (line 21) | public static Encoding GetEncoding(this RconEncoding encoding)
class RconSettingsDp (line 37) | public class RconSettingsDp : DpFile
FILE: NectarRCON/Entity/ClearLogValueMessage.cs
class ClearLogValueMessage (line 2) | public partial class ClearLogValueMessage
FILE: NectarRCON/Entity/Config.cs
class Config (line 4) | public partial class Config
FILE: NectarRCON/Entity/ETheme.cs
type ETheme (line 2) | public enum ETheme : short
FILE: NectarRCON/Entity/Group.cs
class Group (line 6) | public class Group
FILE: NectarRCON/Entity/MainPageLoadValueMessage.cs
class MainPageLoadValueMessage (line 2) | public partial class MainPageLoadValueMessage
FILE: NectarRCON/Entity/ServerInformation.cs
class ServerInformation (line 3) | public class ServerInformation
FILE: NectarRCON/Entity/ServerPassword.cs
class ServerPassword (line 4) | public class ServerPassword
FILE: NectarRCON/Interfaces/IConfigService.cs
type IConfigService (line 4) | public interface IConfigService
method Save (line 6) | void Save();
method GetConfig (line 7) | Config GetConfig();
FILE: NectarRCON/Interfaces/IConnectingDialogService.cs
type IConnectingDialogService (line 4) | public interface IConnectingDialogService
method SetDialog (line 6) | void SetDialog(Grid grid);
method Show (line 7) | void Show();
method Close (line 8) | void Close();
FILE: NectarRCON/Interfaces/IGroupService.cs
type IGroupService (line 6) | public interface IGroupService
method GetGroups (line 11) | IReadOnlyList<Group> GetGroups();
method FindGroup (line 17) | Group? FindGroup(string name);
method GetGroup (line 23) | Group? GetGroup(string groupId);
method Delete (line 29) | void Delete(string groupId);
method Add (line 34) | string Add(Group group);
FILE: NectarRCON/Interfaces/IHistoryService.cs
class HistoryNode (line 3) | public class HistoryNode
type IHistoryService (line 12) | public interface IHistoryService
method Prev (line 19) | HistoryNode? Prev(HistoryNode? current);
method Next (line 26) | HistoryNode? Next(HistoryNode? current);
method InputCmd (line 32) | HistoryNode? InputCmd(string cmd);
FILE: NectarRCON/Interfaces/ILanguageService.cs
type ILanguageService (line 5) | public interface ILanguageService
method Refresh (line 7) | public void Refresh();
method GetSelectedLanguage (line 8) | public ResourceDictionary GetSelectedLanguage();
method GetLanguages (line 9) | public Dictionary<string, ResourceDictionary> GetLanguages();
method SelectLanguage (line 10) | public void SelectLanguage();
method SelectLanguage (line 11) | public void SelectLanguage(string languageName, bool name);
method GetKey (line 12) | public string GetKey(string key);
FILE: NectarRCON/Interfaces/ILogService.cs
type ILogService (line 4) | public interface ILogService
method GetText (line 6) | string GetText();
method Log (line 7) | string Log(string message);
method Clear (line 8) | void Clear();
method SetServer (line 9) | void SetServer(ServerInformation server);
method SetGroup (line 11) | void SetGroup(string groupId);
FILE: NectarRCON/Interfaces/IMessageBoxService.cs
type IMessageBoxService (line 6) | public interface IMessageBoxService
method Show (line 8) | void Show(string message);
method Show (line 9) | void Show(string message, string title);
method Show (line 10) | MessageBoxResult Show(string message, string title, MessageBoxButton b...
method Show (line 11) | void Show(string message, string title, MessageBoxImage image);
method Show (line 12) | MessageBoxResult Show(string message, string title, MessageBoxButton b...
method Show (line 13) | void Show(Exception exception, string? information);
FILE: NectarRCON/Interfaces/IRconConnectionInfoService.cs
type IRconConnectionInfoService (line 5) | public interface IRconConnectionInfoService
method Clear (line 10) | void Clear();
method AddInformation (line 15) | void AddInformation(string serverName);
method GetLastInformation (line 20) | ServerInformation? GetLastInformation();
method GetInformation (line 25) | IReadOnlyList<ServerInformation> GetInformation();
FILE: NectarRCON/Interfaces/IServerInformationService.cs
type IServerInformationService (line 5) | public interface IServerInformationService
method GetServer (line 7) | ServerInformation? GetServer(string name);
method GetServers (line 8) | List<ServerInformation> GetServers();
method AddServer (line 9) | void AddServer(ServerInformation server);
method Save (line 10) | void Save();
method RemoveServer (line 11) | void RemoveServer(string name);
method Update (line 12) | void Update(string name, ServerInformation newInfo);
method ServerIsExist (line 13) | bool ServerIsExist(string name);
FILE: NectarRCON/Interfaces/IServerPasswordService.cs
type IServerPasswordService (line 4) | public interface IServerPasswordService
method Save (line 6) | void Save();
method IsExist (line 7) | bool IsExist(ServerInformation server);
method Set (line 8) | void Set(ServerInformation server, string? password, bool? isEmpty);
method Remove (line 9) | void Remove(ServerInformation server);
method Get (line 10) | ServerPassword? Get(ServerInformation server);
method GetSelect (line 11) | ServerInformation GetSelect();
method Select (line 12) | void Select(ServerInformation server);
FILE: NectarRCON/Models/GroupModel.cs
class GroupModel (line 19) | public partial class GroupModel:ObservableObject
method GroupModel (line 45) | public GroupModel(string name, GroupPageViewModel baseModel)
method Refresh (line 63) | private void Refresh()
method ItemRemove (line 77) | [RelayCommand]
method ConnectCommandCanExecute (line 85) | private bool ConnectCommandCanExecute()
method Connect (line 88) | [RelayCommand(CanExecute = nameof(ConnectCommandCanExecute))]
method Add (line 111) | [RelayCommand]
method Save (line 129) | private void Save()
FILE: NectarRCON/Models/GroupServerItemModel.cs
class GroupServerItemModel (line 4) | public partial class GroupServerItemModel : ObservableObject
method GroupServerItemModel (line 12) | public GroupServerItemModel(string name, GroupModel baseModel)
FILE: NectarRCON/Models/ServerModel.cs
class ServerModel (line 16) | public partial class ServerModel : ObservableObject
method ServerModel (line 41) | public ServerModel(ServerInformation information, ServersPageViewModel...
method EditPass (line 60) | private void EditPass()
method EditPassword (line 67) | [RelayCommand]
method Edit (line 73) | [RelayCommand]
method Delete (line 82) | [RelayCommand]
method Connect (line 96) | [RelayCommand]
FILE: NectarRCON/Rcon/IRconConnection.cs
type IRconConnection (line 6) | public interface IRconConnection
method Connect (line 12) | void Connect();
method Send (line 13) | void Send(string command);
method Close (line 14) | void Close();
method IsConnected (line 15) | bool IsConnected();
method IsConnecting (line 16) | bool IsConnecting();
FILE: NectarRCON/Rcon/RconMultiConnection.cs
class RconMultiConnection (line 21) | internal class RconMultiConnection(
method Close (line 37) | public void Close()
method Connect (line 46) | public void Connect()
method IsConnected (line 102) | public bool IsConnected()
method IsConnecting (line 105) | public bool IsConnecting()
method Send (line 108) | public void Send(string command)
method Dispose (line 134) | public void Dispose()
FILE: NectarRCON/Rcon/RconSingleConnection.cs
class RconSingleConnection (line 15) | public class RconSingleConnection(
method Close (line 34) | public void Close()
method Connect (line 47) | public void Connect()
method IsConnected (line 95) | public bool IsConnected()
method IsConnecting (line 97) | public bool IsConnecting()
method Send (line 99) | public void Send(string command)
FILE: NectarRCON/Services/ApplicationHostService.cs
class ApplicationHostService (line 16) | public class ApplicationHostService(
method StartAsync (line 27) | public async Task StartAsync(CancellationToken cancellationToken)
method StopAsync (line 32) | public async Task StopAsync(CancellationToken cancellationToken)
method LoadConfig (line 36) | private void LoadConfig()
method HandleActivationAsync (line 63) | private async Task HandleActivationAsync()
FILE: NectarRCON/Services/ConfigService.cs
class ConfigService (line 9) | public partial class ConfigService : IConfigService
method ConfigService (line 13) | public ConfigService(ILanguageService languageService)
method GetConfig (line 38) | public Config GetConfig()
method Save (line 40) | public void Save()
FILE: NectarRCON/Services/ConnectingDialogService.cs
class ConnectingDialogService (line 6) | internal class ConnectingDialogService : IConnectingDialogService
method Close (line 9) | public void Close()
method SetDialog (line 16) | public void SetDialog(Grid grid)
method Show (line 21) | public void Show()
FILE: NectarRCON/Services/GroupService.cs
class GroupService (line 12) | public class GroupService : IGroupService
method GroupService (line 20) | public GroupService(IMessageBoxService messageBoxService, ILanguageSer...
method Refresh (line 27) | private void Refresh()
method RemoveGroupInDict (line 64) | private void RemoveGroupInDict(string groupId)
method Add (line 76) | public string Add(Group group)
method Delete (line 94) | public void Delete(string groupId)
method FindGroup (line 104) | public Group? FindGroup(string name)
method GetGroup (line 110) | public Group? GetGroup(string groupId)
method GetGroups (line 116) | public IReadOnlyList<Group> GetGroups()
FILE: NectarRCON/Services/HistoryService.cs
class HistoryService (line 9) | public class HistoryService : IHistoryService
method HistoryService (line 25) | public HistoryService()
method InputCmd (line 46) | public HistoryNode? InputCmd(string cmd)
method AppendNode (line 53) | private HistoryNode? AppendNode(string cmd)
method Next (line 119) | public HistoryNode? Next(HistoryNode? current)
method Prev (line 128) | public HistoryNode? Prev(HistoryNode? current)
method Save (line 141) | private void Save()
FILE: NectarRCON/Services/LanguageService.cs
class LanguageService (line 9) | public class LanguageService : ILanguageService
method LanguageService (line 21) | public LanguageService()
method GetLanguages (line 33) | public Dictionary<string, ResourceDictionary> GetLanguages()
method GetSelectedLanguage (line 35) | public ResourceDictionary GetSelectedLanguage()
method Refresh (line 39) | public void Refresh()
method SelectLanguage (line 72) | public void SelectLanguage()
method SelectLanguage (line 78) | public void SelectLanguage(string languageName, bool name = false)
method GetKey (line 111) | public string GetKey(string key)
FILE: NectarRCON/Services/LogService.cs
class LogService (line 11) | public class LogService : ILogService
method LogService (line 14) | public LogService()
method Clear (line 19) | public void Clear()
method GetText (line 24) | public string GetText()
method Log (line 32) | public string Log(string message)
method SetServer (line 39) | public void SetServer(ServerInformation server)
method SetGroup (line 44) | public void SetGroup(string groupId)
method OpenFile (line 49) | private void OpenFile(string fileName)
FILE: NectarRCON/Services/MessageBoxService.cs
class MessageBoxService (line 6) | public class MessageBoxService : IMessageBoxService
method MessageBoxService (line 10) | public MessageBoxService(ILanguageService languageService)
method Show (line 15) | public void Show(string message)
method Show (line 18) | public void Show(string message, string title)
method Show (line 21) | public MessageBoxResult Show(string message, string title, MessageBoxB...
method Show (line 24) | public void Show(string message, string title, MessageBoxImage image)
method Show (line 27) | public MessageBoxResult Show(string message, string title, MessageBoxB...
method Show (line 30) | public void Show(Exception exception, string? information = null)
FILE: NectarRCON/Services/RconConnectionInfoService.cs
class RconConnectionInfoService (line 12) | public class RconConnectionInfoService : IRconConnectionInfoService
method RconConnectionInfoService (line 16) | public RconConnectionInfoService(IServerInformationService serverInfor...
method AddInformation (line 21) | public void AddInformation(string serverName)
method Clear (line 24) | public void Clear()
method GetInformation (line 27) | public IReadOnlyList<ServerInformation> GetInformation()
method GetLastInformation (line 30) | public ServerInformation? GetLastInformation()
FILE: NectarRCON/Services/ServerInformationService.cs
class ServerInformationService (line 12) | public class ServerInformationService : IServerInformationService
method ServerInformationService (line 18) | public ServerInformationService(ILanguageService languageService)
method AddServer (line 49) | public void AddServer(ServerInformation server)
method GetServer (line 55) | public ServerInformation? GetServer(string name)
method GetServers (line 57) | public List<ServerInformation> GetServers()
method RemoveServer (line 61) | public void RemoveServer(string name)
method Save (line 67) | public void Save()
method ServerIsExist (line 81) | public bool ServerIsExist(string name)
method Update (line 83) | public void Update(string name, ServerInformation newInfo)
FILE: NectarRCON/Services/ServerPasswordService.cs
class ServerPasswordService (line 12) | public class ServerPasswordService : IServerPasswordService
method ServerPasswordService (line 17) | public ServerPasswordService(ILanguageService languageService)
method Get (line 48) | public ServerPassword? Get(ServerInformation server)
method GetSelect (line 57) | public ServerInformation GetSelect()
method IsExist (line 62) | public bool IsExist(ServerInformation server)
method Remove (line 65) | public void Remove(ServerInformation server)
method Save (line 73) | public void Save()
method Select (line 88) | public void Select(ServerInformation server)
method Set (line 93) | public void Set(ServerInformation server, string? password, bool? isEm...
FILE: NectarRCON/ViewModels/AboutPageViewModel.cs
class AboutPageViewModel (line 3) | class AboutPageViewModel
FILE: NectarRCON/ViewModels/AddGroupPageViewModel.cs
class AddGroupPageViewModel (line 9) | public partial class AddGroupPageViewModel:ObservableObject
method AddGroupPageViewModel (line 19) | public AddGroupPageViewModel()
method CanAdd (line 27) | private bool CanAdd()
method Add (line 30) | [RelayCommand(CanExecute = nameof(CanAdd))]
method Cancel (line 48) | [RelayCommand]
method Load (line 54) | [RelayCommand]
FILE: NectarRCON/ViewModels/AddServerWindowViewModel.cs
class AddServerWindowViewModel (line 9) | public partial class AddServerWindowViewModel : ObservableObject
method AddServerWindowViewModel (line 20) | public AddServerWindowViewModel(IServerInformationService serverInform...
method SetWindow (line 25) | public void SetWindow(AddServerWindow window)
method Ok (line 29) | [RelayCommand]
FILE: NectarRCON/ViewModels/EditPasswordWindowViewModel.cs
class EditPasswordWindowViewModel (line 8) | public partial class EditPasswordWindowViewModel : ObservableObject
method EditPasswordWindowViewModel (line 18) | public EditPasswordWindowViewModel()
method SetWindow (line 34) | public void SetWindow(EditPasswordWindow window)
method TextChange (line 38) | [RelayCommand]
method SetPassword (line 43) | [RelayCommand]
FILE: NectarRCON/ViewModels/EditServerWindowViewModel.cs
class EditServerWindowViewModel (line 10) | public partial class EditServerWindowViewModel : ObservableObject
method EditServerWindowViewModel (line 22) | public EditServerWindowViewModel()
method Load (line 29) | [RelayCommand]
method Exit (line 37) | [RelayCommand]
method Ok (line 42) | [RelayCommand]
FILE: NectarRCON/ViewModels/GroupPageViewModel.cs
class GroupPageViewModel (line 10) | public partial class GroupPageViewModel:ObservableObject
method GroupPageViewModel (line 19) | public GroupPageViewModel()
method Load (line 29) | [RelayCommand]
method Refresh (line 35) | private void Refresh()
method RemoveGroup (line 44) | [RelayCommand]
method NewGroup (line 56) | [RelayCommand]
FILE: NectarRCON/ViewModels/JoinGroupWindowViewModel.cs
class JoinGroupWindowViewModel (line 8) | public partial class JoinGroupWindowViewModel:ObservableObject
method JoinGroupWindowViewModel (line 21) | public JoinGroupWindowViewModel()
method OnBlackListChanged (line 38) | partial void OnBlackListChanged(ObservableCollection<string>? value)
FILE: NectarRCON/ViewModels/MainPageViewModel.cs
class MainPageViewModel (line 23) | public partial class MainPageViewModel : ObservableObject
method MainPageViewModel (line 45) | public MainPageViewModel()
method OnClear (line 65) | private void OnClear(object sender, ClearLogValueMessage msg)
method OnMessage (line 71) | private void OnMessage(ServerInformation info, string msg)
method OnClosed (line 81) | private void OnClosed(ServerInformation info)
method Load (line 87) | [RelayCommand]
method ReConnect (line 98) | [RelayCommand]
method ConnectAsync (line 108) | private async Task ConnectAsync()
method OnIsDisconnectionChanged (line 181) | partial void OnIsDisconnectionChanged(bool value)
method OnConnected (line 186) | private void OnConnected(ServerInformation info)
method BackHome (line 193) | [RelayCommand]
method Exit (line 201) | [RelayCommand]
method Run (line 216) | [RelayCommand]
method KeyDown (line 236) | [RelayCommand]
FILE: NectarRCON/ViewModels/MainWindowViewModel.cs
class MainWindowViewModel (line 19) | public partial class MainWindowViewModel : ObservableObject
method MainWindowViewModel (line 27) | public MainWindowViewModel(INavigationService navigationService, ILang...
method OnMainPageChange (line 72) | public void OnMainPageChange(object sender, MainPageLoadValueMessage m...
method OnLoad (line 76) | [RelayCommand]
method ClearButtonClick (line 81) | [RelayCommand]
method ChangePage (line 86) | [RelayCommand]
method ClearProgramLogs (line 92) | [RelayCommand]
FILE: NectarRCON/ViewModels/ServersPageViewModel.cs
class ServersPageViewModel (line 11) | public partial class ServersPageViewModel : ObservableObject
method ServersPageViewModel (line 21) | public ServersPageViewModel()
method Refresh (line 41) | public void Refresh()
method AddServer (line 50) | [RelayCommand]
method FilterTextChanged (line 58) | [RelayCommand]
FILE: NectarRCON/ViewModels/SettingPageViewModel.cs
class SettingPageViewModel (line 16) | public partial class SettingPageViewModel : ObservableObject
method SettingPageViewModel (line 44) | public SettingPageViewModel()
method OnRconAutoReconnectChanged (line 62) | partial void OnRconAutoReconnectChanged(bool value)
method OnIsKeepConnectionWindowOpenChanged (line 68) | partial void OnIsKeepConnectionWindowOpenChanged(bool value)
method OnSelectedRconEncodingChanged (line 74) | partial void OnSelectedRconEncodingChanged(string value)
method PageLoad (line 80) | [RelayCommand]
method Exit (line 97) | [RelayCommand]
method ThemeSelectionChange (line 102) | [RelayCommand]
method LanguageSelectionChange (line 124) | [RelayCommand]
FILE: NectarRCON/Views/Pages/AboutPage.xaml.cs
class AboutPage (line 6) | public partial class AboutPage
method AboutPage (line 8) | public AboutPage()
FILE: NectarRCON/Views/Pages/AddGroupPage.xaml.cs
class AddGroupPage (line 9) | public partial class AddGroupPage : UiPage
method AddGroupPage (line 11) | public AddGroupPage()
FILE: NectarRCON/Views/Pages/GroupPage.xaml.cs
class GroupPage (line 9) | public partial class GroupPage : UiPage
method GroupPage (line 11) | public GroupPage()
method ListView_SelectionChanged (line 16) | private void ListView_SelectionChanged(object sender, SelectionChanged...
FILE: NectarRCON/Views/Pages/MainPage.xaml.cs
class MainPage (line 6) | public partial class MainPage
method MainPage (line 8) | public MainPage()
FILE: NectarRCON/Views/Pages/ServersPage.xaml.cs
class ServersPage (line 6) | public partial class ServersPage
method ServersPage (line 8) | public ServersPage()
FILE: NectarRCON/Views/Pages/SettingPage.xaml.cs
class SettingPage (line 2) | public partial class SettingPage
method SettingPage (line 4) | public SettingPage()
FILE: NectarRCON/Windows/AddServerWindow.xaml.cs
class AddServerWindow (line 9) | public partial class AddServerWindow
method AddServerWindow (line 15) | public AddServerWindow(AddServerWindowViewModel viewModel)
method CancelButtonClick (line 23) | private void CancelButtonClick(object sender, RoutedEventArgs e)
FILE: NectarRCON/Windows/EditPasswordWindow.xaml.cs
class EditPasswordWindow (line 9) | public partial class EditPasswordWindow
method EditPasswordWindow (line 11) | public EditPasswordWindow()
method CancelButtonClick (line 17) | private void CancelButtonClick(object sender, RoutedEventArgs e)
FILE: NectarRCON/Windows/EditServerWindow.xaml.cs
class EditServerWindow (line 6) | public partial class EditServerWindow
method EditServerWindow (line 8) | public EditServerWindow()
FILE: NectarRCON/Windows/JoinGroupWindow.xaml.cs
class JoinGroupWindow (line 22) | public partial class JoinGroupWindow : UiWindow
method JoinGroupWindow (line 25) | public JoinGroupWindow()
method CloseButton_Click (line 29) | private void CloseButton_Click(object sender, RoutedEventArgs e)
method AddBlackList (line 34) | public void AddBlackList(string value)
method ServersListView_SelectionChanged (line 40) | private void ServersListView_SelectionChanged(object sender, Selection...
FILE: NectarRCON/Windows/MainWindow.xaml.cs
class MainWindow (line 14) | public partial class MainWindow : INavigationWindow, INavigableView<Main...
method MainWindow (line 23) | public MainWindow(INavigationService navigationService, MainWindowView...
method GetFrame (line 33) | public Frame GetFrame()
method GetNavigation (line 36) | public INavigation GetNavigation()
method Navigate (line 39) | public bool Navigate(Type pageType)
method SetPageService (line 42) | public void SetPageService(IPageService pageService)
method ShowWindow (line 45) | public void ShowWindow()
method CloseWindow (line 48) | public void CloseWindow()
Condensed preview — 112 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (255K chars).
[
{
"path": ".gitattributes",
"chars": 2518,
"preview": "###############################################################################\n# Set default behavior to automatically "
},
{
"path": ".github/workflows/dotnet-desktop.yml",
"chars": 2691,
"preview": "# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n"
},
{
"path": ".gitignore",
"chars": 6284,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
},
{
"path": "LICENSE.txt",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "NectarRCON/App.xaml",
"chars": 976,
"preview": "<Application\n x:Class=\"NectarRCON.App\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n xml"
},
{
"path": "NectarRCON/App.xaml.cs",
"chars": 4202,
"preview": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing NectarRCON.Interfaces;\nusing "
},
{
"path": "NectarRCON/AssemblyInfo.cs",
"chars": 595,
"preview": "using System.Windows;\n\n[assembly: ThemeInfo(\n ResourceDictionaryLocation.None, //where theme specific resource dictio"
},
{
"path": "NectarRCON/Converters/BoolToVisibilityConverter.cs",
"chars": 665,
"preview": "using System;\nusing System.Windows.Data;\nusing System.Windows;\nusing System.Globalization;\n\nnamespace NectarRCON.Conver"
},
{
"path": "NectarRCON/Converters/IntToVisibilityConverter.cs",
"chars": 1154,
"preview": "using System;\nusing System.Windows.Data;\nusing System.Windows;\nusing System.Globalization;\n\nnamespace NectarRCON.Conver"
},
{
"path": "NectarRCON/Dp/DpFile.cs",
"chars": 2101,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text.Json;\n\nnamespace NectarRCON.Dp;\n\n///"
},
{
"path": "NectarRCON/Dp/RconSettingsDp.cs",
"chars": 1598,
"preview": "using System.Text;\nusing System.Text.Json.Serialization;\n\nnamespace NectarRCON.Dp;\n\npublic enum RconEncoding\n{\n Utf8"
},
{
"path": "NectarRCON/Entity/ClearLogValueMessage.cs",
"chars": 76,
"preview": "namespace NectarRCON.Models;\npublic partial class ClearLogValueMessage\n{\n}\n"
},
{
"path": "NectarRCON/Entity/Config.cs",
"chars": 334,
"preview": "using System.Text.Json.Serialization;\n\nnamespace NectarRCON.Models;\npublic partial class Config\n{\n [JsonPropertyName"
},
{
"path": "NectarRCON/Entity/ETheme.cs",
"chars": 104,
"preview": "namespace NectarRCON.Models;\npublic enum ETheme : short\n{\n System = 0,\n Dark = 1,\n Light = 2\n}"
},
{
"path": "NectarRCON/Entity/Group.cs",
"chars": 408,
"preview": "using System.Collections.Generic;\nusing System.Text.Json.Serialization;\n\nnamespace NectarRCON.Models\n{\n public class"
},
{
"path": "NectarRCON/Entity/MainPageLoadValueMessage.cs",
"chars": 128,
"preview": "namespace NectarRCON.Models;\npublic partial class MainPageLoadValueMessage\n{\n public required bool IsLoaded { get; i"
},
{
"path": "NectarRCON/Entity/ServerInformation.cs",
"chars": 546,
"preview": "using System.Text.Json.Serialization;\nnamespace NectarRCON.Models;\npublic class ServerInformation\n{\n [JsonPropertyNa"
},
{
"path": "NectarRCON/Entity/ServerPassword.cs",
"chars": 355,
"preview": "using System.Text.Json.Serialization;\n\nnamespace NectarRCON.Models;\npublic class ServerPassword\n{\n [JsonPropertyName"
},
{
"path": "NectarRCON/Interfaces/IConfigService.cs",
"chars": 136,
"preview": "using NectarRCON.Models;\n\nnamespace NectarRCON.Interfaces;\npublic interface IConfigService\n{\n void Save();\n Confi"
},
{
"path": "NectarRCON/Interfaces/IConnectingDialogService.cs",
"chars": 177,
"preview": "using System.Windows.Controls;\n\nnamespace NectarRCON.Interfaces;\npublic interface IConnectingDialogService\n{\n void S"
},
{
"path": "NectarRCON/Interfaces/IGroupService.cs",
"chars": 687,
"preview": "using NectarRCON.Models;\nusing System.Collections.Generic;\n\nnamespace NectarRCON.Interfaces;\n\npublic interface IGroupSe"
},
{
"path": "NectarRCON/Interfaces/IHistoryService.cs",
"chars": 684,
"preview": "namespace NectarRCON.Interfaces;\n\npublic class HistoryNode\n{ \n public string? Cmd { get; set; }\n\n public HistoryN"
},
{
"path": "NectarRCON/Interfaces/ILanguageService.cs",
"chars": 410,
"preview": "using System.Collections.Generic;\nusing System.Windows;\n\nnamespace NectarRCON.Interfaces;\npublic interface ILanguageSer"
},
{
"path": "NectarRCON/Interfaces/ILogService.cs",
"chars": 246,
"preview": "using NectarRCON.Models;\n\nnamespace NectarRCON.Interfaces;\npublic interface ILogService\n{\n string GetText();\n str"
},
{
"path": "NectarRCON/Interfaces/IMessageBoxService.cs",
"chars": 538,
"preview": "using System;\nusing System.Windows;\n\nnamespace NectarRCON.Interfaces\n{\n public interface IMessageBoxService\n {\n "
},
{
"path": "NectarRCON/Interfaces/IRconConnectionInfoService.cs",
"chars": 662,
"preview": "using NectarRCON.Models;\nusing System.Collections.Generic;\n\nnamespace NectarRCON.Interfaces;\npublic interface IRconConn"
},
{
"path": "NectarRCON/Interfaces/IServerInformationService.cs",
"chars": 422,
"preview": "using NectarRCON.Models;\nusing System.Collections.Generic;\n\nnamespace NectarRCON.Interfaces;\npublic interface IServerIn"
},
{
"path": "NectarRCON/Interfaces/IServerPasswordService.cs",
"chars": 410,
"preview": "using NectarRCON.Models;\n\nnamespace NectarRCON.Interfaces;\npublic interface IServerPasswordService\n{\n void Save();\n "
},
{
"path": "NectarRCON/Models/GroupModel.cs",
"chars": 4333,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/Models/GroupServerItemModel.cs",
"chars": 551,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\n\nnamespace NectarRCON.Models;\npublic partial class GroupServerItemModel : O"
},
{
"path": "NectarRCON/Models/ServerModel.cs",
"chars": 4335,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/NectarRCON.csproj",
"chars": 1719,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <OutputType>WinExe</OutputType>\n <TargetFramework>net7.0-wi"
},
{
"path": "NectarRCON/Rcon/IRconConnection.cs",
"chars": 484,
"preview": "using NectarRCON.Models;\n\nnamespace NectarRCON.Rcon;\npublic delegate void MessageEvent(ServerInformation information, s"
},
{
"path": "NectarRCON/Rcon/RconMultiConnection.cs",
"chars": 4810,
"preview": "using NectarRCON.Core.Helper;\nusing NectarRCON.Export.Interfaces;\nusing NectarRCON.Interfaces;\nusing NectarRCON.Models;"
},
{
"path": "NectarRCON/Rcon/RconSingleConnection.cs",
"chars": 5088,
"preview": "using NectarRCON.Core.Helper;\nusing NectarRCON.Export.Interfaces;\nusing NectarRCON.Interfaces;\nusing NectarRCON.Models;"
},
{
"path": "NectarRCON/Resources/Languages/en_us.xaml",
"chars": 9963,
"preview": "<ResourceDictionary\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n xmlns:x=\"http://schemas.m"
},
{
"path": "NectarRCON/Resources/Languages/zh_cn.xaml",
"chars": 7713,
"preview": "<ResourceDictionary\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n xmlns:x=\"http://schemas.m"
},
{
"path": "NectarRCON/Resources/Languages/zh_tw.xaml",
"chars": 7711,
"preview": "<ResourceDictionary\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n xmlns:x=\"http://schemas.m"
},
{
"path": "NectarRCON/Services/ApplicationHostService.cs",
"chars": 2473,
"preview": "using Microsoft.Extensions.Hosting;\nusing NectarRCON.Core.Helper;\nusing NectarRCON.Interfaces;\nusing NectarRCON.Models;"
},
{
"path": "NectarRCON/Services/ConfigService.cs",
"chars": 1672,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Models;\nusing System;\nusing System.Diagnostics;\nusing System.IO;\nusing Sy"
},
{
"path": "NectarRCON/Services/ConnectingDialogService.cs",
"chars": 553,
"preview": "using NectarRCON.Interfaces;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace NectarRCON.Services;\ninter"
},
{
"path": "NectarRCON/Services/GroupService.cs",
"chars": 4900,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\n"
},
{
"path": "NectarRCON/Services/HistoryService.cs",
"chars": 3528,
"preview": "using NectarRCON.Interfaces;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\n\n"
},
{
"path": "NectarRCON/Services/LanguageService.cs",
"chars": 4641,
"preview": "using NectarRCON.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing "
},
{
"path": "NectarRCON/Services/LogService.cs",
"chars": 1614,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Models;\nusing System;\nusing System.IO;\nusing System.Text;\nusing System.Te"
},
{
"path": "NectarRCON/Services/MessageBoxService.cs",
"chars": 1332,
"preview": "using NectarRCON.Interfaces;\nusing System;\nusing System.Windows;\n\nnamespace NectarRCON.Services;\npublic class MessageBo"
},
{
"path": "NectarRCON/Services/RconConnectionInfoService.cs",
"chars": 1030,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq"
},
{
"path": "NectarRCON/Services/ServerInformationService.cs",
"chars": 3278,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Diag"
},
{
"path": "NectarRCON/Services/ServerPasswordService.cs",
"chars": 3868,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Diag"
},
{
"path": "NectarRCON/ViewModels/AboutPageViewModel.cs",
"chars": 78,
"preview": "namespace NectarRCON.ViewModels\n{\n class AboutPageViewModel\n {\n }\n}\n"
},
{
"path": "NectarRCON/ViewModels/AddGroupPageViewModel.cs",
"chars": 1506,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/ViewModels/AddServerWindowViewModel.cs",
"chars": 2064,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/ViewModels/EditPasswordWindowViewModel.cs",
"chars": 1481,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/ViewModels/EditServerWindowViewModel.cs",
"chars": 2028,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/ViewModels/GroupPageViewModel.cs",
"chars": 2004,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/ViewModels/JoinGroupWindowViewModel.cs",
"chars": 1192,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing NectarRCON.Interfaces;\nusing System.Collections.Generic;\nusing System"
},
{
"path": "NectarRCON/ViewModels/MainPageViewModel.cs",
"chars": 9743,
"preview": "using System;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing CommunityToolkit.Mvv"
},
{
"path": "NectarRCON/ViewModels/MainWindowViewModel.cs",
"chars": 3964,
"preview": "using System;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing CommunityToolkit.Mvv"
},
{
"path": "NectarRCON/ViewModels/ServersPageViewModel.cs",
"chars": 1847,
"preview": "using CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Interfaces;\nusing Necta"
},
{
"path": "NectarRCON/ViewModels/SettingPageViewModel.cs",
"chars": 4589,
"preview": "using System;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing CommunityToolkit.Mvvm.Input;\nusing NectarRCON.Core.Help"
},
{
"path": "NectarRCON/Views/Pages/AboutPage.xaml",
"chars": 2592,
"preview": "<ui:UiPage\n x:Class=\"NectarRCON.Views.Pages.AboutPage\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/prese"
},
{
"path": "NectarRCON/Views/Pages/AboutPage.xaml.cs",
"chars": 233,
"preview": "namespace NectarRCON.Views.Pages\n{\n /// <summary>\n /// AboutPage.xaml 的交互逻辑\n /// </summary>\n public partial"
},
{
"path": "NectarRCON/Views/Pages/AddGroupPage.xaml",
"chars": 3139,
"preview": "<ui:UiPage\n x:Class=\"NectarRCON.Views.Pages.AddGroupPage\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/pr"
},
{
"path": "NectarRCON/Views/Pages/AddGroupPage.xaml.cs",
"chars": 289,
"preview": "using System;\nusing Wpf.Ui.Controls;\n\nnamespace NectarRCON.Views.Pages\n{\n /// <summary>\n /// AddGroupPage.xaml 的交"
},
{
"path": "NectarRCON/Views/Pages/GroupPage.xaml",
"chars": 7524,
"preview": "<ui:UiPage\n x:Class=\"NectarRCON.Views.Pages.GroupPage\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/prese"
},
{
"path": "NectarRCON/Views/Pages/GroupPage.xaml.cs",
"chars": 527,
"preview": "using System.Windows.Controls;\nusing Wpf.Ui.Controls;\n\nnamespace NectarRCON.Views.Pages\n{\n /// <summary>\n /// Gro"
},
{
"path": "NectarRCON/Views/Pages/MainPage.xaml",
"chars": 7101,
"preview": "<ui:UiPage x:Class=\"NectarRCON.Views.Pages.MainPage\"\n xmlns:ui=\"http://schemas.lepo.co/wpfui/2022/xaml\"\n xmln"
},
{
"path": "NectarRCON/Views/Pages/MainPage.xaml.cs",
"chars": 230,
"preview": "namespace NectarRCON.Views.Pages\n{\n /// <summary>\n /// MainPage.xaml 的交互逻辑\n /// </summary>\n public partial "
},
{
"path": "NectarRCON/Views/Pages/ServersPage.xaml",
"chars": 4742,
"preview": "<ui:UiPage\n x:Class=\"NectarRCON.Views.Pages.ServersPage\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/pre"
},
{
"path": "NectarRCON/Views/Pages/ServersPage.xaml.cs",
"chars": 239,
"preview": "namespace NectarRCON.Views.Pages\n{\n /// <summary>\n /// ServersPage.xaml 的交互逻辑\n /// </summary>\n public parti"
},
{
"path": "NectarRCON/Views/Pages/SettingPage.xaml",
"chars": 4805,
"preview": "<ui:UiPage x:Class=\"NectarRCON.Views.Pages.SettingPage\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/prese"
},
{
"path": "NectarRCON/Views/Pages/SettingPage.xaml.cs",
"chars": 140,
"preview": "namespace NectarRCON.Views.Pages;\npublic partial class SettingPage\n{\n public SettingPage()\n {\n InitializeC"
},
{
"path": "NectarRCON/Windows/AddServerWindow.xaml",
"chars": 3477,
"preview": "<ui:UiWindow x:Class=\"NectarRCON.Windows.AddServerWindow\"\n xmlns:ui=\"http://schemas.lepo.co/wpfui/2022/xaml\"\n "
},
{
"path": "NectarRCON/Windows/AddServerWindow.xaml.cs",
"chars": 624,
"preview": "using NectarRCON.ViewModels;\nusing System.Windows;\n\nnamespace NectarRCON.Windows\n{\n /// <summary>\n /// AddServerW"
},
{
"path": "NectarRCON/Windows/EditPasswordWindow.xaml",
"chars": 3304,
"preview": "<ui:UiWindow x:Class=\"NectarRCON.Windows.EditPasswordWindow\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xam"
},
{
"path": "NectarRCON/Windows/EditPasswordWindow.xaml.cs",
"chars": 483,
"preview": "using NectarRCON.ViewModels;\nusing System.Windows;\n\nnamespace NectarRCON.Windows\n{\n /// <summary>\n /// EditPasswo"
},
{
"path": "NectarRCON/Windows/EditServerWindow.xaml",
"chars": 4155,
"preview": "<ui:UiWindow x:Class=\"NectarRCON.Windows.EditServerWindow\"\n xmlns:ui=\"http://schemas.lepo.co/wpfui/2022/xaml\"\n "
},
{
"path": "NectarRCON/Windows/EditServerWindow.xaml.cs",
"chars": 250,
"preview": "namespace NectarRCON.Windows\n{\n /// <summary>\n /// EditServerWindow.xaml 的交互逻辑\n /// </summary>\n public part"
},
{
"path": "NectarRCON/Windows/JoinGroupWindow.xaml",
"chars": 2711,
"preview": "<ui:UiWindow\n x:Class=\"NectarRCON.Windows.JoinGroupWindow\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/p"
},
{
"path": "NectarRCON/Windows/JoinGroupWindow.xaml.cs",
"chars": 1321,
"preview": "using NectarRCON.ViewModels;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusin"
},
{
"path": "NectarRCON/Windows/MainWindow.xaml",
"chars": 5496,
"preview": "<ui:UiWindow x:Class=\"NectarRCON.MainWindow\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentat"
},
{
"path": "NectarRCON/Windows/MainWindow.xaml.cs",
"chars": 1625,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.ViewModels;\nusing System;\nusing System.Windows.Controls;\nusing Wpf.Ui.Com"
},
{
"path": "NectarRCON/app.manifest",
"chars": 2757,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n <ass"
},
{
"path": "NectarRCON.Adapter.Minecraft/MinecraftRconClient.cs",
"chars": 2747,
"preview": "using NectarRCON.Export.Client;\nusing NectarRCON.Export.Interfaces;\nusing System.ComponentModel;\nusing System.Text;\n\nna"
},
{
"path": "NectarRCON.Adapter.Minecraft/NectarRCON.Adapter.Minecraft.csproj",
"chars": 326,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>net7.0-windows</TargetFramework>\n <Implici"
},
{
"path": "NectarRCON.Adapter.Minecraft/Packet.cs",
"chars": 1011,
"preview": "using System.Text;\n\nnamespace NectarRCON.Adapter.Minecraft;\npublic class Packet\n{\n public readonly int Length;\n p"
},
{
"path": "NectarRCON.Adapter.Minecraft/PacketEncoder.cs",
"chars": 1483,
"preview": "using System.Text;\n\nnamespace NectarRCON.Adapter.Minecraft\n{\n public enum PacketType : int\n {\n Response, /"
},
{
"path": "NectarRCON.Adapter.Minecraft/README.md",
"chars": 28,
"preview": "# Adapter\n\nMinecraftRcon实现\n"
},
{
"path": "NectarRCON.Core/Helper/AdapterHelpers.cs",
"chars": 309,
"preview": "using NectarRCON.Adapter.Minecraft;\nusing NectarRCON.Export.Interfaces;\nnamespace NectarRCON.Core.Helper\n{\n public s"
},
{
"path": "NectarRCON.Core/Helper/DNSHelpers.cs",
"chars": 1015,
"preview": "using DnsClient;\n\nnamespace NectarRCON.Core.Helper\n{\n public class DNSHelpers\n {\n public static string AQu"
},
{
"path": "NectarRCON.Core/Helper/Win32Helper.cs",
"chars": 691,
"preview": "namespace NectarRCON.Core.Helper;\npublic static class Win32Helper\n{\n public static bool GetWindowsTheme()\n {\n "
},
{
"path": "NectarRCON.Core/NectarRCON.Core.csproj",
"chars": 519,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>net7.0-windows</TargetFramework>\n <Implicit"
},
{
"path": "NectarRCON.Export/Client/BaseTcpClient.cs",
"chars": 1481,
"preview": "using NectarRCON.Export.Interfaces;\nusing System.Net.Sockets;\nusing System.Text;\n\nnamespace NectarRCON.Export.Client;\n/"
},
{
"path": "NectarRCON.Export/Interfaces/IRconAdapter.cs",
"chars": 648,
"preview": "using System.Text;\n\nnamespace NectarRCON.Export.Interfaces;\n/// <summary>\n/// Rcon协议兼容接口\n/// </summary>\npublic interfac"
},
{
"path": "NectarRCON.Export/Interfaces/IRconClient.cs",
"chars": 694,
"preview": "namespace NectarRCON.Export.Interfaces;\n/// <summary>\n/// Rcon客户端接口\n/// </summary>\npublic interface IRconClient : IDisp"
},
{
"path": "NectarRCON.Export/NectarRCON.Export.csproj",
"chars": 327,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>net7.0-windows</TargetFramework>\n <Implicit"
},
{
"path": "NectarRCON.Tests/Adapter/MinecraftRconTest.cs",
"chars": 1261,
"preview": "using NectarRCON.Adapter.Minecraft;\nusing NectarRCON.Export.Interfaces;\n\nnamespace NectarRCON.Tests.Adapter\n{\n [Test"
},
{
"path": "NectarRCON.Tests/DNSHelperTests.cs",
"chars": 692,
"preview": "using NectarRCON.Core.Helper;\nnamespace NectarRCON.Tests\n{\n [TestClass]\n public class DNSHelperTests\n {\n "
},
{
"path": "NectarRCON.Tests/GroupServiceTests.cs",
"chars": 2149,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Models;\nusing NectarRCON.Services;\nusing System.Windows;\n\nnamespace Necta"
},
{
"path": "NectarRCON.Tests/MessageBoxServiceTests.cs",
"chars": 1327,
"preview": "using NectarRCON.Interfaces;\nusing NectarRCON.Services;\nusing System.Windows;\n\nnamespace NectarRCON.Tests\n{\n [TestCl"
},
{
"path": "NectarRCON.Tests/NectarRCON.Tests.csproj",
"chars": 1050,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>net7.0-windows</TargetFramework>\n <Implicit"
},
{
"path": "NectarRCON.Tests/UpdaterTests.cs",
"chars": 1148,
"preview": "using NectarRCON.Updater;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing S"
},
{
"path": "NectarRCON.Tests/Usings.cs",
"chars": 58,
"preview": "global using Microsoft.VisualStudio.TestTools.UnitTesting;"
},
{
"path": "NectarRCON.Updater/AppVersion.cs",
"chars": 3805,
"preview": "using System.Runtime.CompilerServices;\nusing System.Text.RegularExpressions;\n\nnamespace NectarRCON.Updater\n{\n public"
},
{
"path": "NectarRCON.Updater/GithubUpdater.cs",
"chars": 3192,
"preview": "using NectarRCON.Updater.Model;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nu"
},
{
"path": "NectarRCON.Updater/IUpdater.cs",
"chars": 572,
"preview": "namespace NectarRCON.Updater\n{\n public interface IUpdater\n {\n /// <summary>\n /// 设置版本\n /// <"
},
{
"path": "NectarRCON.Updater/Model/Asset.cs",
"chars": 380,
"preview": "using System.Text.Json.Serialization;\n\nnamespace NectarRCON.Updater.Model\n{\n public class Asset\n {\n [JsonP"
},
{
"path": "NectarRCON.Updater/Model/Release.cs",
"chars": 697,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json.Serializat"
},
{
"path": "NectarRCON.Updater/NectarRCON.Updater.csproj",
"chars": 214,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>net7.0-windows</TargetFramework>\n <Implicit"
},
{
"path": "NectarRCON.sln",
"chars": 3631,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.4.3320"
},
{
"path": "README.md",
"chars": 1741,
"preview": "\n<h1 align=\"center\">\n<img src=\"NectarRCON/Resources/Icon.png\" style=\"image-rendering: optimizeSpeed;image-rendering: -mo"
},
{
"path": "README_EN.md",
"chars": 2386,
"preview": "<h1 align=\"center\">\n<img src=\"NectarRCON/Resources/Icon.png\" style=\"image-rendering: optimizeSpeed;image-rendering: -moz"
}
]
About this extraction
This page contains the full source code of the zkhssb/NectarRCON GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 112 files (224.2 KB), approximately 55.8k tokens, and a symbol index with 392 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.