├── .editorconfig ├── .github └── workflows │ └── dotnet-desktop.yml ├── .gitignore ├── .gitmodules ├── GamerVII.Launcher.sln ├── README.md ├── src └── GamerVII.Launcher │ ├── App.axaml │ ├── App.axaml.cs │ ├── Assets │ ├── Resources │ │ └── Styles.axaml │ ├── avalonia-logo.ico │ ├── background.jpg │ ├── close.svg │ ├── document.svg │ ├── download.svg │ ├── edit.svg │ ├── leftArrow.svg │ ├── logo.png │ ├── logo.svg │ ├── logout.svg │ ├── minecraft.png │ ├── plus-white.svg │ ├── plus.svg │ ├── profile.svg │ ├── progress-bar-circle.svg │ ├── promo.png │ ├── rightArrow.svg │ ├── settings.svg │ ├── tg.svg │ ├── users.svg │ └── vk.svg │ ├── Extensions │ ├── AttachedProperties.cs │ └── ServiceRegister.cs │ ├── GamerVII.Launcher.csproj │ ├── Models │ ├── Client │ │ ├── CustomMinecraftPath.cs │ │ ├── GameClient.cs │ │ ├── IGameClient.cs │ │ ├── ILocalSettings.cs │ │ ├── IMinecraftVersion.cs │ │ ├── IStartupOptions.cs │ │ ├── LocalSettings.cs │ │ ├── MinecraftVersion.cs │ │ └── StartupOptions.cs │ ├── Entities │ │ └── LogItem.cs │ ├── Enums │ │ └── ModLoaderType.cs │ └── Users │ │ ├── IUser.cs │ │ └── User.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Services │ ├── Auth │ │ ├── AuthService.cs │ │ ├── EmptyAuthService.cs │ │ └── IAuthService.cs │ ├── Client │ │ ├── IGameClientsService.cs │ │ └── LocalGameClientService.cs │ ├── GameLaunch │ │ ├── GameLaunchService.cs │ │ └── IGameLaunchService.cs │ ├── LocalStorage │ │ ├── ILocalStorageService.cs │ │ └── LocalStorageService.cs │ ├── Logger │ │ ├── DatabaseLoggerService.cs │ │ └── ILoggerService.cs │ └── System │ │ ├── ISystemService.cs │ │ └── SystemService.cs │ ├── ViewLocator.cs │ ├── ViewModels │ ├── Base │ │ ├── PageViewModelBase.cs │ │ └── ViewModelBase.cs │ ├── MainWindowViewModel.cs │ ├── Pages │ │ ├── AddClientPageViewModel.cs │ │ ├── AuthPageViewModel.cs │ │ ├── ModsPageViewModel.cs │ │ ├── ProfilePageViewModel.cs │ │ └── SettingsPageViewModel.cs │ ├── ServersListViewModel.cs │ └── SidebarViewModel.cs │ ├── Views │ ├── Components │ │ ├── ButtonControl.axaml │ │ ├── ButtonControl.axaml.cs │ │ ├── DownloadStatusComponent.axaml │ │ ├── DownloadStatusComponent.axaml.cs │ │ ├── FolderPickerControl.axaml │ │ ├── FolderPickerControl.axaml.cs │ │ ├── LogoutButton.axaml │ │ ├── LogoutButton.axaml.cs │ │ ├── ServerContent.axaml │ │ ├── ServerContent.axaml.cs │ │ ├── ServersListView.axaml │ │ ├── ServersListView.axaml.cs │ │ ├── SidebarView.axaml │ │ └── SidebarView.axaml.cs │ ├── Converters │ │ ├── IsNotNullConverter.cs │ │ ├── ListNotEmptyConverter.cs │ │ ├── ReleaseDateFromMinecraftVersionConverter.cs │ │ └── ReverseBoolValueConverter.cs │ ├── MainWindow.axaml │ ├── MainWindow.axaml.cs │ └── Pages │ │ ├── AddClientPageView.axaml │ │ ├── AddClientPageView.axaml.cs │ │ ├── AuthPageView.axaml │ │ ├── AuthPageView.axaml.cs │ │ ├── ModsPageView.axaml │ │ ├── ModsPageView.axaml.cs │ │ ├── ProfilePageView.axaml │ │ ├── ProfilePageView.axaml.cs │ │ ├── SettingsPageView.axaml │ │ └── SettingsPageView.axaml.cs │ ├── app.manifest │ └── icon.ico └── tests └── GamerVII.Launcher.Tests ├── GameClientsTests.cs ├── GamerVII.Launcher.Tests.csproj ├── GlobalUsings.cs ├── LoginTests.cs └── SettingsViewModelTests.cs /.editorconfig: -------------------------------------------------------------------------------- 1 | ########################################## 2 | # Common Settings 3 | ########################################## 4 | 5 | # This file is the top-most EditorConfig file 6 | root = true 7 | 8 | # All Files 9 | [*] 10 | charset = utf-8 11 | indent_style = space 12 | indent_size = 4 13 | insert_final_newline = true 14 | trim_trailing_whitespace = true 15 | 16 | ########################################## 17 | # File Extension Settings 18 | ########################################## 19 | 20 | # Visual Studio Solution Files 21 | [*.sln] 22 | indent_style = tab 23 | 24 | # Visual Studio XML Project Files 25 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 26 | indent_size = 2 27 | 28 | # Various XML Configuration Files 29 | [*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}] 30 | indent_size = 2 31 | 32 | # JSON Files 33 | [*.{json,json5}] 34 | indent_size = 2 35 | 36 | # YAML Files 37 | [*.{yml,yaml}] 38 | indent_size = 2 39 | 40 | # Markdown Files 41 | [*.md] 42 | trim_trailing_whitespace = false 43 | 44 | # Web Files 45 | [*.{htm,html,js,ts,tsx,css,sass,scss,less,svg,vue}] 46 | indent_size = 2 47 | 48 | # Batch Files 49 | [*.{cmd,bat}] 50 | end_of_line = crlf 51 | 52 | # Bash Files 53 | [*.sh] 54 | end_of_line = lf -------------------------------------------------------------------------------- /.github/workflows/dotnet-desktop.yml: -------------------------------------------------------------------------------- 1 | name: GamerVII.Launcher.Pipeline 2 | 3 | on: 4 | push: 5 | branches: [ "main", "dev" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | strategy: 14 | matrix: 15 | configuration: [ Debug ] 16 | 17 | runs-on: windows-latest 18 | 19 | env: 20 | Solution_Name: GamerVII.Launcher.sln 21 | Test_Project_Path: tests/GamerVII.Launcher.Tests 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v3 26 | with: 27 | fetch-depth: 0 28 | submodules: recursive 29 | 30 | # Install submodules 31 | - uses: actions/checkout@v2 32 | - name: Checkout submodules 33 | shell: bash 34 | run: | 35 | auth_header="$(git config --local --get http.https://github.com/.extraheader)" 36 | git submodule sync --recursive 37 | git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 38 | 39 | # Install the .NET Core workload 40 | - name: Install .NET Core 41 | uses: actions/setup-dotnet@v3 42 | with: 43 | dotnet-version: 7.0.x 44 | 45 | # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild 46 | - name: Setup MSBuild.exe 47 | uses: microsoft/setup-msbuild@v1.0.2 48 | 49 | # Execute all unit tests in the solution 50 | - name: Execute unit tests 51 | run: dotnet test 52 | 53 | # Restore the application to populate the obj folder with RuntimeIdentifiers 54 | - name: Restore the application 55 | run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration 56 | env: 57 | Configuration: ${{ matrix.configuration }} 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # Db folder from docker compose 14 | db/ 15 | 16 | # User-specific files (MonoDevelop/Xamarin Studio) 17 | *.userprefs 18 | 19 | # Mono auto generated files 20 | mono_crash.* 21 | 22 | # Build results 23 | [Dd]ebug/ 24 | [Dd]ebugPublic/ 25 | [Rr]elease/ 26 | [Rr]eleases/ 27 | x64/ 28 | x86/ 29 | [Ww][Ii][Nn]32/ 30 | [Aa][Rr][Mm]/ 31 | [Aa][Rr][Mm]64/ 32 | bld/ 33 | [Bb]in/ 34 | [Oo]bj/ 35 | [Ll]og/ 36 | [Ll]ogs/ 37 | 38 | # Visual Studio 2015/2017 cache/options directory 39 | .vs/ 40 | .vscode/ 41 | # Uncomment if you have tasks that create the project's static files in wwwroot 42 | #wwwroot/ 43 | 44 | # Visual Studio 2017 auto generated files 45 | Generated\ Files/ 46 | 47 | # MSTest test Results 48 | [Tt]est[Rr]esult*/ 49 | [Bb]uild[Ll]og.* 50 | 51 | # NUnit 52 | *.VisualState.xml 53 | TestResult.xml 54 | nunit-*.xml 55 | 56 | # Build Results of an ATL Project 57 | [Dd]ebugPS/ 58 | [Rr]eleasePS/ 59 | dlldata.c 60 | 61 | # Benchmark Results 62 | BenchmarkDotNet.Artifacts/ 63 | 64 | # .NET Core 65 | project.lock.json 66 | project.fragment.lock.json 67 | artifacts/ 68 | 69 | # Tye 70 | .tye/ 71 | 72 | # ASP.NET Scaffolding 73 | ScaffoldingReadMe.txt 74 | 75 | # StyleCop 76 | StyleCopReport.xml 77 | 78 | # Files built by Visual Studio 79 | *_i.c 80 | *_p.c 81 | *_h.h 82 | *.ilk 83 | *.meta 84 | *.obj 85 | *.iobj 86 | *.pch 87 | *.pdb 88 | *.ipdb 89 | *.pgc 90 | *.pgd 91 | *.rsp 92 | *.sbr 93 | *.tlb 94 | *.tli 95 | *.tlh 96 | *.tmp 97 | *.tmp_proj 98 | *_wpftmp.csproj 99 | *.log 100 | *.vspscc 101 | *.vssscc 102 | .builds 103 | *.pidb 104 | *.svclog 105 | *.scc 106 | 107 | # Chutzpah Test files 108 | _Chutzpah* 109 | 110 | # Visual C++ cache files 111 | ipch/ 112 | *.aps 113 | *.ncb 114 | *.opendb 115 | *.opensdf 116 | *.sdf 117 | *.cachefile 118 | *.VC.db 119 | *.VC.VC.opendb 120 | 121 | # Visual Studio profiler 122 | *.psess 123 | *.vsp 124 | *.vspx 125 | *.sap 126 | 127 | # Visual Studio Trace Files 128 | *.e2e 129 | 130 | # TFS 2012 Local Workspace 131 | $tf/ 132 | 133 | # Guidance Automation Toolkit 134 | *.gpState 135 | 136 | # ReSharper is a .NET coding add-in 137 | _ReSharper*/ 138 | *.[Rr]e[Ss]harper 139 | *.DotSettings.user 140 | 141 | # TeamCity is a build add-in 142 | _TeamCity* 143 | 144 | # DotCover is a Code Coverage Tool 145 | *.dotCover 146 | 147 | # AxoCover is a Code Coverage Tool 148 | .axoCover/* 149 | !.axoCover/settings.json 150 | 151 | # Coverlet is a free, cross platform Code Coverage Tool 152 | coverage*.json 153 | coverage*.xml 154 | coverage*.info 155 | 156 | # Visual Studio code coverage results 157 | *.coverage 158 | *.coveragexml 159 | 160 | # NCrunch 161 | _NCrunch_* 162 | .*crunch*.local.xml 163 | nCrunchTemp_* 164 | 165 | # MightyMoose 166 | *.mm.* 167 | AutoTest.Net/ 168 | 169 | # Web workbench (sass) 170 | .sass-cache/ 171 | 172 | # Installshield output folder 173 | [Ee]xpress/ 174 | 175 | # DocProject is a documentation generator add-in 176 | DocProject/buildhelp/ 177 | DocProject/Help/*.HxT 178 | DocProject/Help/*.HxC 179 | DocProject/Help/*.hhc 180 | DocProject/Help/*.hhk 181 | DocProject/Help/*.hhp 182 | DocProject/Help/Html2 183 | DocProject/Help/html 184 | 185 | # Click-Once directory 186 | publish/ 187 | 188 | # Publish Web Output 189 | *.[Pp]ublish.xml 190 | *.azurePubxml 191 | # Note: Comment the next line if you want to checkin your web deploy settings, 192 | # but database connection strings (with potential passwords) will be unencrypted 193 | *.pubxml 194 | *.publishproj 195 | 196 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 197 | # checkin your Azure Web App publish settings, but sensitive information contained 198 | # in these scripts will be unencrypted 199 | PublishScripts/ 200 | 201 | # NuGet Packages 202 | *.nupkg 203 | # NuGet Symbol Packages 204 | *.snupkg 205 | # The packages folder can be ignored because of Package Restore 206 | **/[Pp]ackages/* 207 | # except build/, which is used as an MSBuild target. 208 | !**/[Pp]ackages/build/ 209 | # Uncomment if necessary however generally it will be regenerated when needed 210 | #!**/[Pp]ackages/repositories.config 211 | # NuGet v3's project.json files produces more ignorable files 212 | *.nuget.props 213 | *.nuget.targets 214 | 215 | # Microsoft Azure Build Output 216 | csx/ 217 | *.build.csdef 218 | 219 | # Microsoft Azure Emulator 220 | ecf/ 221 | rcf/ 222 | 223 | # Windows Store app package directories and files 224 | AppPackages/ 225 | BundleArtifacts/ 226 | Package.StoreAssociation.xml 227 | _pkginfo.txt 228 | *.appx 229 | *.appxbundle 230 | *.appxupload 231 | 232 | # Visual Studio cache files 233 | # files ending in .cache can be ignored 234 | *.[Cc]ache 235 | # but keep track of directories ending in .cache 236 | !?*.[Cc]ache/ 237 | 238 | # Others 239 | ClientBin/ 240 | ~$* 241 | *~ 242 | *.dbmdl 243 | *.dbproj.schemaview 244 | *.jfm 245 | *.pfx 246 | *.publishsettings 247 | orleans.codegen.cs 248 | 249 | # Including strong name files can present a security risk 250 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 251 | #*.snk 252 | 253 | # Since there are multiple workflows, uncomment next line to ignore bower_components 254 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 255 | #bower_components/ 256 | 257 | # RIA/Silverlight projects 258 | Generated_Code/ 259 | 260 | # Backup & report files from converting an old project file 261 | # to a newer Visual Studio version. Backup files are not needed, 262 | # because we have git ;-) 263 | _UpgradeReport_Files/ 264 | Backup*/ 265 | UpgradeLog*.XML 266 | UpgradeLog*.htm 267 | ServiceFabricBackup/ 268 | *.rptproj.bak 269 | 270 | # SQL Server files 271 | *.mdf 272 | *.ldf 273 | *.ndf 274 | 275 | # Business Intelligence projects 276 | *.rdl.data 277 | *.bim.layout 278 | *.bim_*.settings 279 | *.rptproj.rsuser 280 | *- [Bb]ackup.rdl 281 | *- [Bb]ackup ([0-9]).rdl 282 | *- [Bb]ackup ([0-9][0-9]).rdl 283 | 284 | # Microsoft Fakes 285 | FakesAssemblies/ 286 | 287 | # GhostDoc plugin setting file 288 | *.GhostDoc.xml 289 | 290 | # Node.js Tools for Visual Studio 291 | .ntvs_analysis.dat 292 | node_modules/ 293 | 294 | # Visual Studio 6 build log 295 | *.plg 296 | 297 | # Visual Studio 6 workspace options file 298 | *.opt 299 | 300 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 301 | *.vbw 302 | 303 | # Visual Studio LightSwitch build output 304 | **/*.HTMLClient/GeneratedArtifacts 305 | **/*.DesktopClient/GeneratedArtifacts 306 | **/*.DesktopClient/ModelManifest.xml 307 | **/*.Server/GeneratedArtifacts 308 | **/*.Server/ModelManifest.xml 309 | _Pvt_Extensions 310 | 311 | # Paket dependency manager 312 | .paket/paket.exe 313 | paket-files/ 314 | 315 | # FAKE - F# Make 316 | .fake/ 317 | 318 | # CodeRush personal settings 319 | .cr/personal 320 | 321 | # Python Tools for Visual Studio (PTVS) 322 | __pycache__/ 323 | *.pyc 324 | 325 | # Cake - Uncomment if you are using it 326 | # tools/** 327 | # !tools/packages.config 328 | 329 | # Tabs Studio 330 | *.tss 331 | 332 | # Telerik's JustMock configuration file 333 | *.jmconfig 334 | 335 | # BizTalk build output 336 | *.btp.cs 337 | *.btm.cs 338 | *.odx.cs 339 | *.xsd.cs 340 | 341 | # OpenCover UI analysis results 342 | OpenCover/ 343 | 344 | # Azure Stream Analytics local run output 345 | ASALocalRun/ 346 | 347 | # MSBuild Binary and Structured Log 348 | *.binlog 349 | 350 | # NVidia Nsight GPU debugger configuration file 351 | *.nvuser 352 | 353 | # MFractors (Xamarin productivity tool) working folder 354 | .mfractor/ 355 | 356 | # Local History for Visual Studio 357 | .localhistory/ 358 | 359 | # BeatPulse healthcheck temp database 360 | healthchecksdb 361 | 362 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 363 | MigrationBackup/ 364 | 365 | # Ionide (cross platform F# VS Code tools) working folder 366 | .ionide/ 367 | 368 | # Fody - auto-generated XML schema 369 | FodyWeavers.xsd 370 | 371 | ## 372 | ## Visual studio for Mac 373 | ## 374 | 375 | 376 | # globs 377 | Makefile.in 378 | *.userprefs 379 | *.usertasks 380 | config.make 381 | config.status 382 | aclocal.m4 383 | install-sh 384 | autom4te.cache/ 385 | *.tar.gz 386 | tarballs/ 387 | test-results/ 388 | 389 | # Mac bundle stuff 390 | *.dmg 391 | *.app 392 | 393 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 394 | # General 395 | .DS_Store 396 | .AppleDouble 397 | .LSOverride 398 | 399 | # Icon must end with two \r 400 | Icon 401 | 402 | 403 | # Thumbnails 404 | ._* 405 | 406 | # Files that might appear in the root of a volume 407 | .DocumentRevisions-V100 408 | .fseventsd 409 | .Spotlight-V100 410 | .TemporaryItems 411 | .Trashes 412 | .VolumeIcon.icns 413 | .com.apple.timemachine.donotpresent 414 | 415 | # Directories potentially created on remote AFP share 416 | .AppleDB 417 | .AppleDesktop 418 | Network Trash Folder 419 | Temporary Items 420 | .apdisk 421 | 422 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 423 | # Windows thumbnail cache files 424 | Thumbs.db 425 | ehthumbs.db 426 | ehthumbs_vista.db 427 | 428 | # Dump file 429 | *.stackdump 430 | 431 | # Folder config file 432 | [Dd]esktop.ini 433 | 434 | # Recycle Bin used on file shares 435 | $RECYCLE.BIN/ 436 | 437 | # Windows Installer files 438 | *.cab 439 | *.msi 440 | *.msix 441 | *.msm 442 | *.msp 443 | 444 | # Windows shortcuts 445 | *.lnk 446 | 447 | # JetBrains Rider 448 | .idea/ 449 | *.sln.iml 450 | 451 | ## 452 | ## Visual Studio Code 453 | ## 454 | .vscode/* 455 | !.vscode/settings.json 456 | !.vscode/tasks.json 457 | !.vscode/launch.json 458 | !.vscode/extensions.json -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/GamerVII.Notification.Avalonia"] 2 | path = src/GamerVII.Notification.Avalonia 3 | url = https://github.com/GamerVII-NET/GamerVII.Notification.Avalonia.git 4 | -------------------------------------------------------------------------------- /GamerVII.Launcher.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.33913.275 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{662268E9-BD01-43C7-924B-F4F285C8D391}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{09A80297-F0EB-4A8F-8CD1-20DF8AD12D38}" 9 | ProjectSection(SolutionItems) = preProject 10 | README.md = README.md 11 | .editorconfig = .editorconfig 12 | .gitignore = .gitignore 13 | .gitmodules = .gitmodules 14 | EndProjectSection 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GamerVII.Launcher", "src\GamerVII.Launcher\GamerVII.Launcher.csproj", "{31859677-ACD0-48C0-A4EB-502CDBB7F07A}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{793FCF04-CB68-4093-9A0F-57A0CA4475AA}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GamerVII.Launcher.Tests", "tests\GamerVII.Launcher.Tests\GamerVII.Launcher.Tests.csproj", "{787232DD-3F4F-4B12-8297-455C9A4C3A43}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GamerVII.Notification.Avalonia", "src\GamerVII.Notification.Avalonia\GamerVII.Notification.Avalonia\GamerVII.Notification.Avalonia.csproj", "{B792AA78-60F3-4EEF-B0FD-129ACD2ACD89}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {31859677-ACD0-48C0-A4EB-502CDBB7F07A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {31859677-ACD0-48C0-A4EB-502CDBB7F07A}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {31859677-ACD0-48C0-A4EB-502CDBB7F07A}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {31859677-ACD0-48C0-A4EB-502CDBB7F07A}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {787232DD-3F4F-4B12-8297-455C9A4C3A43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {787232DD-3F4F-4B12-8297-455C9A4C3A43}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {787232DD-3F4F-4B12-8297-455C9A4C3A43}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {787232DD-3F4F-4B12-8297-455C9A4C3A43}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {B792AA78-60F3-4EEF-B0FD-129ACD2ACD89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {B792AA78-60F3-4EEF-B0FD-129ACD2ACD89}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {B792AA78-60F3-4EEF-B0FD-129ACD2ACD89}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {B792AA78-60F3-4EEF-B0FD-129ACD2ACD89}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {E0375879-A52D-4581-81EF-7A27063F494F} 48 | EndGlobalSection 49 | GlobalSection(NestedProjects) = preSolution 50 | {31859677-ACD0-48C0-A4EB-502CDBB7F07A} = {662268E9-BD01-43C7-924B-F4F285C8D391} 51 | {787232DD-3F4F-4B12-8297-455C9A4C3A43} = {793FCF04-CB68-4093-9A0F-57A0CA4475AA} 52 | {B792AA78-60F3-4EEF-B0FD-129ACD2ACD89} = {662268E9-BD01-43C7-924B-F4F285C8D391} 53 | EndGlobalSection 54 | EndGlobal 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![image](https://github.com/GamerVII-NET/minecraft-vanilla-launcher/assets/111225722/36740818-6ba3-4dbc-a431-ba3c9a041409) 3 | 4 | 5 | GamerVII Launcher 6 | ======= 7 | The Minecraft Launcher is a user-friendly application designed to streamline the process of launching Minecraft and managing game settings. It provides an intuitive interface and essential features to enhance the Minecraft gaming experience. 8 | 9 | Install command 10 | ``` 11 | git clone --recursive https://github.com/GamerVII-NET/minecraft-vanilla-launcher.git 12 | ``` 13 | 14 | # implemented functionality / ToDo 15 | - [x] Authorization by nickname 16 | - [x] Creating game clients 17 | - [x] Deleting game clients (Right-click on the project) 18 | - [ ] Advanced client editing capabilities 19 | • Changing the client after creation 20 | • The ability to install a custom icon 21 | - [ ] Reinstalling the client / fixing errors 22 | - [ ] Ability to duplicate builds 23 | - [ ] The ability to add global resource packs, worlds 24 | - [ ] Connect the Morinth API 25 | - [ ] The ability to share assemblies 26 | - [ ] Switchable DiscordRPC with information output (https://github.com/Lachee/discord-rpc-csharp) 27 | - [ ] Support for Neoforce and Quilt 28 | - [ ] Quick Builds / Random Builds (Own or Unpack) 29 | - [ ] Viewing logs with error highlighting, warns, info 30 | - [ ] Customization of the launcher 31 | - [ ] The ability to add a license account, an account ely.by (Skin system) 32 | - [ ] Ability to limit the number of simultaneous downloads/recordings for weak/slow PCs 33 | - [ ] The ability to globally and separately select Java 17 and 8 for new and old versions of the main 34 | - [ ] Ability to set java arguments and variables 35 | - [ ] Add the ability to translate the launcher into different languages 36 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/App.axaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | #008C45 25 | #36008C45 26 | #047A3D 27 | 28 | #0E0E0E 29 | #181818 30 | 31 | #151515 32 | #2F2F2F 33 | #1B1B1B 34 | #2C2C2C 35 | #353535 36 | 37 | #FFFFFF 38 | #989898 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | using GamerVII.Launcher.ViewModels; 5 | using GamerVII.Launcher.Views; 6 | 7 | namespace GamerVII.Launcher 8 | { 9 | public class App : Application 10 | { 11 | public override void Initialize() 12 | { 13 | AvaloniaXamlLoader.Load(this); 14 | } 15 | 16 | public override void OnFrameworkInitializationCompleted() 17 | { 18 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 19 | { 20 | desktop.MainWindow = new MainWindow 21 | { 22 | DataContext = new MainWindowViewModel(), 23 | }; 24 | 25 | } 26 | 27 | base.OnFrameworkInitializationCompleted(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/Resources/Styles.axaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 10 | 11 | 20 | 21 | 28 | 29 | 31 | 32 | 37 | 38 | 41 | 42 | 45 | 46 | 49 | 50 | 53 | 54 | 57 | 58 | 61 | 62 | 66 | 67 | 73 | 74 | 80 | 81 | 88 | 89 | 95 | 96 | 100 | 101 | 105 | 106 | 109 | 110 | 113 | 114 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 136 | 137 | 142 | 143 | 151 | 152 | 157 | 158 | 161 | 162 | 165 | 166 | 176 | 177 | 181 | 182 | 186 | 190 | 191 | 201 | 202 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/avalonia-logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamerVII-NET/minecraft-vanilla-launcher/00a0c21ea532e2bfb42f5adcb475fc87508617b2/src/GamerVII.Launcher/Assets/avalonia-logo.ico -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamerVII-NET/minecraft-vanilla-launcher/00a0c21ea532e2bfb42f5adcb475fc87508617b2/src/GamerVII.Launcher/Assets/background.jpg -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/document.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/leftArrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamerVII-NET/minecraft-vanilla-launcher/00a0c21ea532e2bfb42f5adcb475fc87508617b2/src/GamerVII.Launcher/Assets/logo.png -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/minecraft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamerVII-NET/minecraft-vanilla-launcher/00a0c21ea532e2bfb42f5adcb475fc87508617b2/src/GamerVII.Launcher/Assets/minecraft.png -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/plus-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/profile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/progress-bar-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamerVII-NET/minecraft-vanilla-launcher/00a0c21ea532e2bfb42f5adcb475fc87508617b2/src/GamerVII.Launcher/Assets/promo.png -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/rightArrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/tg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/users.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Assets/vk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Extensions/AttachedProperties.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Extensions; 2 | 3 | public class AttachedProperties 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Extensions/ServiceRegister.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using GamerVII.Launcher.Services.Auth; 3 | using GamerVII.Launcher.Services.Client; 4 | using GamerVII.Launcher.Services.GameLaunch; 5 | using GamerVII.Launcher.Services.LocalStorage; 6 | using GamerVII.Launcher.Services.Logger; 7 | using GamerVII.Launcher.Services.System; 8 | using GamerVII.Notification.Avalonia; 9 | using Splat; 10 | 11 | namespace GamerVII.Launcher.Extensions; 12 | 13 | public static class ServiceRegister 14 | { 15 | 16 | public static AppBuilder RegisterServices(this AppBuilder builder) 17 | { 18 | RegisterServices(); 19 | 20 | return builder; 21 | } 22 | 23 | public static void RegisterServices() 24 | { 25 | Locator.CurrentMutable.RegisterConstant(new LocalStorageService(), typeof(ILocalStorageService)); 26 | Locator.CurrentMutable.RegisterConstant(new DatabaseLoggerService(), typeof(ILoggerService)); 27 | Locator.CurrentMutable.RegisterConstant(new SystemService(), typeof(ISystemService)); 28 | Locator.CurrentMutable.RegisterConstant(new LocalGameClientService(), typeof(IGameClientService)); 29 | Locator.CurrentMutable.RegisterConstant(new GameLaunchService(), typeof(IGameLaunchService)); 30 | Locator.CurrentMutable.RegisterConstant(new EmptyAuthService(), typeof(IAuthService)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/GamerVII.Launcher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | WinExe 4 | net7.0 5 | enable 6 | true 7 | app.manifest 8 | true 9 | icon.ico 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ServersListView.axaml 42 | 43 | 44 | SidebarView.axaml 45 | 46 | 47 | IStartupOptions.cs 48 | 49 | 50 | IGameClient.cs 51 | 52 | 53 | IUser.cs 54 | 55 | 56 | IGameLaunchService.cs 57 | 58 | 59 | ILocalSettings.cs 60 | 61 | 62 | IAuthService.cs 63 | 64 | 65 | IAuthService.cs 66 | 67 | 68 | IGameClientsService.cs 69 | 70 | 71 | ILoggerService.cs 72 | 73 | 74 | IGameClientsService.cs 75 | 76 | 77 | IGameLaunchService.cs 78 | 79 | 80 | IAuthService.cs 81 | 82 | 83 | IAuthService.cs 84 | 85 | 86 | IMinecraftVersion.cs 87 | 88 | 89 | ILocalStorageService.cs 90 | 91 | 92 | ISystemService.cs 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/CustomMinecraftPath.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using CmlLib.Core; 3 | 4 | namespace GamerVII.Launcher.Models.Client; 5 | 6 | public class CustomMinecraftPath : MinecraftPath 7 | { 8 | public CustomMinecraftPath(string basePath) 9 | { 10 | BasePath = NormalizePath(basePath); 11 | 12 | Library = NormalizePath(Path.Combine(BasePath, "libraries")); 13 | Versions = NormalizePath(Path.Combine(BasePath, "clients")); 14 | Resource = NormalizePath(Path.Combine(BasePath, "resources")); 15 | 16 | Runtime = NormalizePath(Path.Combine(BasePath, "java")); 17 | Assets = NormalizePath(Path.Combine(BasePath, "assets")); 18 | 19 | CreateDirs(); 20 | } 21 | 22 | public override string GetVersionJarPath(string id) => NormalizePath($"{Versions}/{id}/client.jar"); 23 | 24 | public override string GetVersionJsonPath(string id) => NormalizePath($"{Versions}/{id}/client.json"); 25 | 26 | public override string GetAssetObjectPath(string assetId) => NormalizePath($"{Assets}/files"); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/GameClient.cs: -------------------------------------------------------------------------------- 1 | using GamerVII.Launcher.Models.Enums; 2 | 3 | namespace GamerVII.Launcher.Models.Client; 4 | 5 | public class GameClient : IGameClient 6 | { 7 | public string Name { get; set; } = string.Empty; 8 | public string Version { get; set; } = string.Empty; 9 | public string InstallationVersion { get; set; } = null!; 10 | public string Description { get; set; } = string.Empty; 11 | public object? Image { get; set; } 12 | public ModLoaderType ModLoaderType { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/IGameClient.cs: -------------------------------------------------------------------------------- 1 | using GamerVII.Launcher.Models.Enums; 2 | 3 | namespace GamerVII.Launcher.Models.Client; 4 | public interface IGameClient 5 | { 6 | string Name { get; set; } 7 | string Version { get; set; } 8 | string InstallationVersion { get; set; } 9 | string Description { get; set; } 10 | object? Image { get; set; } 11 | ModLoaderType ModLoaderType { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/ILocalSettings.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Models.Client; 2 | 3 | public interface ILocalSettings 4 | { 5 | int MemorySize { get; set; } 6 | int WindowWidth { get; set; } 7 | int WindowHeight { get; set; } 8 | bool IsFullScreen { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/IMinecraftVersion.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Models.Client; 2 | 3 | public interface IMinecraftVersion 4 | { 5 | public string Version { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/IStartupOptions.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Models.Client; 2 | 3 | public interface IStartupOptions 4 | { 5 | int MinimumRamMb { get; set; } 6 | int MaximumRamMb { get; set; } 7 | bool FullScreen { get; set; } 8 | int ScreenWidth { get; set; } 9 | int ScreenHeight { get; set; } 10 | string? ServerIp { get; set; } 11 | int ServerPort { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/LocalSettings.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Models.Client; 2 | 3 | public class LocalSettings : ILocalSettings 4 | { 5 | public int MemorySize { get; set; } 6 | public int WindowWidth { get; set; } 7 | public int WindowHeight { get; set; } 8 | public bool IsFullScreen { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/MinecraftVersion.cs: -------------------------------------------------------------------------------- 1 | using CmlLib.Core.VersionMetadata; 2 | 3 | namespace GamerVII.Launcher.Models.Client; 4 | 5 | public class MinecraftVersion : IMinecraftVersion 6 | { 7 | public string Version { get; set; } 8 | public MVersionMetadata MVersion { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Client/StartupOptions.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Models.Client; 2 | 3 | public class StartupOptions : IStartupOptions 4 | { 5 | public int MinimumRamMb { get; set; } 6 | public int MaximumRamMb { get; set; } 7 | public bool FullScreen { get; set; } 8 | public int ScreenWidth { get; set; } 9 | public int ScreenHeight { get; set; } 10 | public string? ServerIp { get; set; } 11 | public int ServerPort { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Entities/LogItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SQLite; 3 | 4 | namespace GamerVII.Launcher.Models.Entities; 5 | 6 | [Table("Logs")] 7 | public class LogItem 8 | { 9 | public string Date { get; set; } = null!; 10 | public string Message { get; set; } = null!; 11 | public string? StackTrace { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Enums/ModLoaderType.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Models.Enums; 2 | public enum ModLoaderType 3 | { 4 | /// 5 | /// Minecraft default loader 6 | /// 7 | Vanilla = 0, 8 | /// 9 | /// Minecraft forge loader 10 | /// 11 | Forge = 1, 12 | /// 13 | /// minecraft Fabric loader 14 | /// 15 | Fabric = 2, 16 | /// 17 | /// minecraft Lite loader 18 | /// 19 | LiteLoader = 3 20 | } 21 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Users/IUser.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.Models.Users; 2 | public interface IUser 3 | { 4 | string Login { get; set; } 5 | string Password { get; set; } 6 | bool IsLogin { get; set; } 7 | string? AccessToken { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Models/Users/User.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace GamerVII.Launcher.Models.Users; 3 | 4 | public class User : IUser 5 | { 6 | public string Login { get; set; } = null!; 7 | public string Password { get; set; } = null!; 8 | public bool IsLogin { get; set; } 9 | public string? AccessToken { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.ReactiveUI; 3 | using GamerVII.Launcher.Extensions; 4 | using System; 5 | using System.Reactive; 6 | using CmlLib.Core.Version; 7 | using GamerVII.Launcher.Services.Logger; 8 | using ReactiveUI; 9 | using Splat; 10 | 11 | namespace GamerVII.Launcher 12 | { 13 | internal class Program 14 | { 15 | private static ILoggerService _loggerService; 16 | 17 | [STAThread] 18 | public static void Main(string[] args) 19 | { 20 | 21 | #if !DEBUG 22 | RxApp.DefaultExceptionHandler = Observer.Create(GlobalExceptionHandler); 23 | #endif 24 | 25 | BuildAvaloniaApp() 26 | .StartWithClassicDesktopLifetime(args); 27 | } 28 | 29 | private static void GlobalExceptionHandler(Exception exception) 30 | { 31 | _loggerService.Log(exception.Message, exception); 32 | } 33 | 34 | 35 | public static AppBuilder BuildAvaloniaApp() 36 | { 37 | 38 | var app = AppBuilder.Configure() 39 | .UsePlatformDetect() 40 | .WithInterFont() 41 | .LogToTrace() 42 | .RegisterServices() 43 | .UseReactiveUI(); 44 | 45 | _loggerService = Locator.Current.GetService() ?? throw new Exception($"{nameof(ILoggerService)} not registered"); 46 | 47 | return app; 48 | 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "GamerVII.Launcher": { 4 | "commandName": "Project" 5 | }, 6 | "WSL": { 7 | "commandName": "WSL2", 8 | "distributionName": "" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/Auth/AuthService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | using GamerVII.Launcher.Models.Users; 7 | using GamerVII.Launcher.Services.LocalStorage; 8 | using Splat; 9 | 10 | namespace GamerVII.Launcher.Services.Auth; 11 | 12 | public class AuthService : IAuthService 13 | { 14 | private readonly ILocalStorageService _localStorage; 15 | private readonly HttpClient _httpClient; 16 | 17 | public AuthService(ILocalStorageService? localStorage = null) 18 | { 19 | _httpClient = new HttpClient 20 | { 21 | BaseAddress = new Uri("http://localhost") 22 | }; 23 | 24 | _localStorage = localStorage 25 | ?? Locator.Current.GetService() 26 | ?? throw new Exception($"{nameof(ILocalStorageService)} not registered"); 27 | } 28 | 29 | public async Task OnLogin(string login, string password) 30 | { 31 | var user = new User 32 | { 33 | Login = login, 34 | Password = password 35 | }; 36 | 37 | var request = new HttpRequestMessage(HttpMethod.Post, $"{_httpClient.BaseAddress!.AbsoluteUri}/auth.php"); 38 | 39 | var content = new MultipartFormDataContent(); 40 | content.Add(new StringContent(user.Login), "login"); 41 | content.Add(new StringContent(user.Password), "password"); 42 | 43 | request.Content = content; 44 | var response = await _httpClient.SendAsync(request); 45 | 46 | if (response.StatusCode != HttpStatusCode.OK) return user; 47 | 48 | var result = await response.Content.ReadAsStringAsync(); 49 | user.IsLogin = true; 50 | user.AccessToken = result; 51 | var refreshToken = response.Headers.FirstOrDefault(c => c.Key == "Refresh-Token").Value.FirstOrDefault() ?? 52 | string.Empty; 53 | 54 | await _localStorage.SetAsync("RefreshToken", refreshToken); 55 | await _localStorage.SetAsync("User", user); 56 | 57 | return user; 58 | } 59 | 60 | public async Task OnLogout() 61 | { 62 | await _localStorage.SetAsync("RefreshToken", string.Empty); 63 | await _localStorage.SetAsync("User", string.Empty); 64 | } 65 | 66 | public async Task GetAuthorizedUser() 67 | { 68 | return await _localStorage.GetAsync("User") ?? new User { Login = string.Empty, Password = string.Empty }; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/Auth/EmptyAuthService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using GamerVII.Launcher.Models.Users; 4 | using GamerVII.Launcher.Services.LocalStorage; 5 | using Splat; 6 | 7 | namespace GamerVII.Launcher.Services.Auth; 8 | 9 | public class EmptyAuthService : IAuthService 10 | { 11 | private readonly ILocalStorageService _localStorage; 12 | 13 | public EmptyAuthService(ILocalStorageService? localStorage = null) 14 | { 15 | _localStorage = localStorage 16 | ?? Locator.Current.GetService() 17 | ?? throw new Exception(nameof(ILocalStorageService) + " not registered"); 18 | } 19 | 20 | public async Task GetAuthorizedUser() 21 | { 22 | var user = await _localStorage.GetAsync("User"); 23 | 24 | return user ?? new User { Login = string.Empty, Password = string.Empty}; 25 | } 26 | 27 | public Task OnLogin(string login, string password) 28 | { 29 | var user = new User 30 | { 31 | Login = login, 32 | Password = password, 33 | AccessToken = string.Empty, 34 | IsLogin = true 35 | }; 36 | 37 | _localStorage.SetAsync("User", user); 38 | 39 | return Task.FromResult((IUser)user); 40 | } 41 | 42 | public Task OnLogout() 43 | { 44 | var user = new User 45 | { 46 | Login = string.Empty, 47 | Password = string.Empty, 48 | AccessToken = string.Empty, 49 | IsLogin = false 50 | }; 51 | 52 | return _localStorage.SetAsync("User", user); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/Auth/IAuthService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GamerVII.Launcher.Models.Users; 3 | 4 | namespace GamerVII.Launcher.Services.Auth; 5 | 6 | /// 7 | /// Represents the service for managing user authentication. 8 | /// 9 | public interface IAuthService 10 | { 11 | /// 12 | /// Retrieves the authorized user. 13 | /// 14 | /// An instance of IUser representing the authorized user. 15 | Task GetAuthorizedUser(); 16 | 17 | /// 18 | /// Performs login operation using the provided login credentials. 19 | /// 20 | /// The user's login. 21 | /// The user's password. 22 | /// An instance of IUser representing the authenticated user. 23 | Task OnLogin(string login, string password); 24 | 25 | /// 26 | /// Performs logout operation for the currently authenticated user. 27 | /// 28 | Task OnLogout(); 29 | } 30 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/Client/IGameClientsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using GamerVII.Launcher.Models.Client; 4 | 5 | namespace GamerVII.Launcher.Services.Client; 6 | 7 | /// 8 | /// Represents a service for managing game clients. 9 | /// 10 | public interface IGameClientService 11 | { 12 | /// 13 | /// Retrieves a collection of game clients asynchronously. 14 | /// 15 | /// An asynchronous operation that yields a collection of IGameClient instances. 16 | Task> GetClientsAsync(); 17 | } 18 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/Client/LocalGameClientService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using GamerVII.Launcher.Models.Client; 4 | using GamerVII.Launcher.Models.Enums; 5 | 6 | namespace GamerVII.Launcher.Services.Client; 7 | 8 | public class LocalGameClientService : IGameClientService 9 | { 10 | public async Task> GetClientsAsync() 11 | { 12 | var servers = new List(); 13 | 14 | // servers.Add(new GameClient 15 | // { 16 | // Name = $"Название сервера", 17 | // Image = null, 18 | // Description = "Описание", 19 | // Version = "1.7.10", 20 | // ModLoaderType = ModLoaderType.Vanilla 21 | // }); 22 | 23 | return await Task.FromResult(servers); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/GameLaunch/GameLaunchService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using CmlLib.Core; 10 | using CmlLib.Core.Auth; 11 | using CmlLib.Core.Installer.Forge; 12 | using GamerVII.Launcher.Models.Client; 13 | using GamerVII.Launcher.Models.Users; 14 | using GamerVII.Launcher.Services.Logger; 15 | using GamerVII.Launcher.Services.System; 16 | using Splat; 17 | 18 | namespace GamerVII.Launcher.Services.GameLaunch; 19 | 20 | public class GameLaunchService : IGameLaunchService 21 | { 22 | private readonly ISystemService _systemService; 23 | private readonly ILoggerService _loggerService; 24 | private CMLauncher? _launcher; 25 | 26 | public event IGameLaunchService.ProgressChangedEventHandler? ProgressChanged; 27 | public event IGameLaunchService.FileChangedEventHandler? FileChanged; 28 | public event IGameLaunchService.LoadClientEventHandler? LoadClientEnded; 29 | 30 | public GameLaunchService(ILoggerService? loggerService = null, ISystemService? systemService = null) 31 | { 32 | _systemService = systemService 33 | ?? Locator.Current.GetService() 34 | ?? throw new Exception($"{nameof(ISystemService)} not registered"); 35 | 36 | _loggerService = loggerService 37 | ?? Locator.Current.GetService() 38 | ?? throw new Exception($"{nameof(ILoggerService)} not registered"); 39 | 40 | ServicePointManager.DefaultConnectionLimit = 256; 41 | 42 | } 43 | 44 | public async Task InitMinecraftLauncher() 45 | { 46 | var gamePath = await _systemService.GetGamePath(); 47 | 48 | var path = new CustomMinecraftPath(gamePath); 49 | 50 | _launcher = new CMLauncher(path); 51 | 52 | _launcher.ProgressChanged += (_, e) => ProgressChanged?.Invoke(e.ProgressPercentage); 53 | _launcher.FileChanged += (e) => 54 | { 55 | if (e.FileName != null) 56 | FileChanged?.Invoke(e.FileName); 57 | }; 58 | 59 | return _launcher; 60 | } 61 | 62 | public async Task LaunchClient(IGameClient client, IUser user, IStartupOptions startupOptions) 63 | { 64 | _launcher ??= await InitMinecraftLauncher(); 65 | 66 | // var session = new MSession(user.Login, user.AccessToken, "uuid"); 67 | var session = MSession.CreateOfflineSession(user.Login); 68 | 69 | var process = await _launcher.CreateProcessAsync(client.InstallationVersion, new MLaunchOption 70 | { 71 | JavaPath = _launcher.GetDefaultJavaPath()?.Replace("javaw.exe", "java.exe"), 72 | MinimumRamMb = startupOptions.MinimumRamMb, 73 | MaximumRamMb = startupOptions.MaximumRamMb, 74 | FullScreen = startupOptions.FullScreen, 75 | ScreenHeight = startupOptions.ScreenHeight, 76 | ScreenWidth = startupOptions.ScreenWidth, 77 | ServerIp = startupOptions.ServerIp, 78 | ServerPort = startupOptions.ServerPort, 79 | Session = session, 80 | }, false); 81 | 82 | process.EnableRaisingEvents = true; 83 | process.StartInfo.RedirectStandardError = true; 84 | process.StartInfo.RedirectStandardOutput = true; 85 | process.StartInfo.UseShellExecute = false; 86 | process.StartInfo.CreateNoWindow = true; 87 | 88 | 89 | process.ErrorDataReceived += (_, e) => 90 | { 91 | if (e.Data != null) 92 | _loggerService.Log(e.Data); 93 | }; 94 | process.OutputDataReceived += (_, e) => 95 | { 96 | if (e.Data != null) 97 | _loggerService.Log(e.Data); 98 | }; 99 | 100 | process.Start(); 101 | process.BeginErrorReadLine(); 102 | process.BeginOutputReadLine(); 103 | 104 | return process; 105 | } 106 | 107 | public Task LoadClient(IGameClient client) 108 | { 109 | var thread = new Thread(() => LoadClientFiles(client)) 110 | { 111 | IsBackground = true 112 | }; 113 | 114 | thread.Start(); 115 | 116 | return Task.FromResult(client); 117 | } 118 | 119 | public async Task> GetAvailableVersions() 120 | { 121 | _launcher ??= await InitMinecraftLauncher(); 122 | 123 | var versions = await _launcher.GetAllVersionsAsync(); 124 | 125 | return versions.Select(c => new MinecraftVersion 126 | { 127 | Version = c.Name, 128 | MVersion = c 129 | }) 130 | .OrderByDescending(c => c.MVersion.ReleaseTime); 131 | } 132 | 133 | private async void LoadClientFiles(IGameClient client) 134 | { 135 | try 136 | { 137 | _launcher ??= await InitMinecraftLauncher(); 138 | 139 | var version = await _launcher.GetVersionAsync(client.Version); 140 | client.InstallationVersion = version.Id; 141 | 142 | switch (client.ModLoaderType) 143 | { 144 | case Models.Enums.ModLoaderType.Vanilla: 145 | 146 | if (!File.Exists(_launcher.MinecraftPath.GetVersionJarPath(client.Version))) 147 | await _launcher.CheckAndDownloadAsync(version); 148 | 149 | break; 150 | 151 | case Models.Enums.ModLoaderType.Forge: 152 | await LoadForge(client); 153 | break; 154 | 155 | case Models.Enums.ModLoaderType.Fabric: 156 | break; 157 | case Models.Enums.ModLoaderType.LiteLoader: 158 | break; 159 | } 160 | 161 | LoadClientEnded?.Invoke(client, true, "success"); 162 | } 163 | catch (Exception ex) 164 | { 165 | LoadClientEnded?.Invoke(client, false, ex.Message); 166 | } 167 | } 168 | 169 | private async Task LoadForge(IGameClient client) 170 | { 171 | _launcher ??= await InitMinecraftLauncher(); 172 | 173 | var forge = new MForge(_launcher); 174 | forge.FileChanged += (e) => 175 | { 176 | if (e.FileName != null) FileChanged?.Invoke(e.FileName); 177 | }; 178 | forge.ProgressChanged += (_, e) => ProgressChanged?.Invoke(e.ProgressPercentage); 179 | 180 | client.InstallationVersion = await forge.Install(client.Version); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/GameLaunch/IGameLaunchService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Threading.Tasks; 4 | using GamerVII.Launcher.Models.Client; 5 | using GamerVII.Launcher.Models.Users; 6 | 7 | namespace GamerVII.Launcher.Services.GameLaunch; 8 | 9 | /// 10 | /// Represents a service for launching and managing Minecraft game clients. 11 | /// 12 | public interface IGameLaunchService 13 | { 14 | /// 15 | /// Delegate for handling the event when loading a client ends. 16 | /// 17 | /// The Minecraft client instance to launch. 18 | /// True if loading the client ended successfully, otherwise false. 19 | /// An optional message related to the loading outcome. 20 | delegate void LoadClientEventHandler(IGameClient client, bool loadClientEnded, string? message); 21 | 22 | /// 23 | /// Delegate for handling the event when the progress changes during client loading or downloading. 24 | /// 25 | /// The percentage of progress completed. 26 | delegate void ProgressChangedEventHandler(decimal percentage); 27 | 28 | /// 29 | /// Delegate for handling the event when a file changes during client loading or downloading. 30 | /// 31 | /// The message related to the file change. 32 | delegate void FileChangedEventHandler(string message); 33 | 34 | /// 35 | /// Event raised when loading a client ends. 36 | /// 37 | event LoadClientEventHandler LoadClientEnded; 38 | 39 | /// 40 | /// Event raised when the progress changes during client loading or downloading. 41 | /// 42 | event ProgressChangedEventHandler ProgressChanged; 43 | 44 | /// 45 | /// Event raised when a file changes during client loading or downloading. 46 | /// 47 | event FileChangedEventHandler FileChanged; 48 | 49 | /// 50 | /// Launches a specific Minecraft client. 51 | /// 52 | /// The Minecraft client instance to launch. 53 | /// The user for whom the client is being launched. 54 | /// Launch Parameters 55 | /// The process responsible for launching the client. 56 | Task LaunchClient(IGameClient client, IUser user, IStartupOptions startupOptions); 57 | 58 | /// 59 | /// Downloads a Minecraft client of a certain version. 60 | /// 61 | /// The Minecraft client instance to download. 62 | /// Client information required to run. 63 | Task LoadClient(IGameClient client); 64 | 65 | Task> GetAvailableVersions(); 66 | } 67 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/LocalStorage/ILocalStorageService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace GamerVII.Launcher.Services.LocalStorage; 4 | 5 | /// 6 | /// Represents a service for managing local storage. 7 | /// 8 | public interface ILocalStorageService 9 | { 10 | /// 11 | /// Sets the value of an item in the local storage asynchronously. 12 | /// 13 | /// The type of the value to store. 14 | /// The key associated with the item. 15 | /// The value to store. 16 | /// An asynchronous operation representing the completion of the set operation. 17 | Task SetAsync(string key, T value); 18 | 19 | /// 20 | /// Gets the value of an item from the local storage asynchronously. 21 | /// 22 | /// The type of the value to retrieve. 23 | /// The key associated with the item. 24 | /// An asynchronous operation that yields the retrieved value. 25 | Task GetAsync(string key); 26 | 27 | /// 28 | /// Sets the value of an item in the local storage asynchronously. 29 | /// 30 | /// The type of the value to retrieve. 31 | /// The value to store. 32 | /// An asynchronous operation that yields the retrieved value. 33 | Task SaveRecord(T value); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/LocalStorage/LocalStorageService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GamerVII.Launcher.Models.Entities; 3 | using Newtonsoft.Json; 4 | using SQLite; 5 | 6 | namespace GamerVII.Launcher.Services.LocalStorage; 7 | 8 | public class LocalStorageService : ILocalStorageService 9 | { 10 | private const string DatabasePath = "data.db"; 11 | private readonly SQLiteAsyncConnection _database; 12 | 13 | public LocalStorageService() 14 | { 15 | _database = new SQLiteAsyncConnection(DatabasePath); 16 | 17 | InitializeTables(); 18 | } 19 | 20 | private void InitializeTables() 21 | { 22 | _database.CreateTableAsync().Wait(); 23 | _database.CreateTableAsync().Wait(); 24 | } 25 | 26 | public async Task SetAsync(string key, T value) 27 | { 28 | var serializedValue = JsonConvert.SerializeObject(value); 29 | var storageItem = new StorageItem 30 | { 31 | Key = key, 32 | TypeName = typeof(T).FullName, 33 | Value = serializedValue 34 | }; 35 | await _database.InsertOrReplaceAsync(storageItem); 36 | } 37 | 38 | public async Task GetAsync(string key) 39 | { 40 | var storageItem = await _database.Table() 41 | .Where(si => si.Key == key) 42 | .FirstOrDefaultAsync(); 43 | 44 | if (storageItem != null) 45 | { 46 | return JsonConvert.DeserializeObject(storageItem.Value); 47 | } 48 | 49 | return default(T); 50 | } 51 | 52 | public Task SaveRecord(T record) 53 | { 54 | return _database.InsertOrReplaceAsync(record); 55 | } 56 | 57 | [Table("StorageItems")] 58 | private class StorageItem 59 | { 60 | [PrimaryKey] public string Key { get; set; } = null!; 61 | public string? TypeName { get; set; } 62 | public string Value { get; set; } = null!; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/Logger/DatabaseLoggerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using GamerVII.Launcher.Models.Entities; 5 | using GamerVII.Launcher.Services.LocalStorage; 6 | using Splat; 7 | 8 | namespace GamerVII.Launcher.Services.Logger; 9 | 10 | public class DatabaseLoggerService : ILoggerService 11 | { 12 | private readonly ILocalStorageService _storageService; 13 | 14 | public DatabaseLoggerService(ILocalStorageService? storageService = null) 15 | { 16 | _storageService = storageService 17 | ?? Locator.Current.GetService() 18 | ?? throw new Exception($"{nameof(ILocalStorageService)} not registered!"); 19 | } 20 | 21 | public async Task Log(string message) 22 | { 23 | Console.WriteLine(message); 24 | 25 | var logItem = new LogItem 26 | { 27 | Message = message, 28 | Date = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss / zz"), 29 | }; 30 | 31 | await _storageService.SaveRecord(logItem); 32 | } 33 | 34 | public async Task Log(string message, Exception exception) 35 | { 36 | 37 | Console.WriteLine(message); 38 | 39 | var logItem = new LogItem 40 | { 41 | Message = message, 42 | Date = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss / zz"), 43 | StackTrace = exception.StackTrace 44 | }; 45 | 46 | await _storageService.SaveRecord(logItem); 47 | } 48 | 49 | public void Dispose() 50 | { 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/Logger/ILoggerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace GamerVII.Launcher.Services.Logger; 5 | 6 | /// 7 | /// Defines a logger service contract for logging messages. 8 | /// 9 | public interface ILoggerService : IDisposable 10 | { 11 | /// 12 | /// Logs the specified message. 13 | /// 14 | /// The message to be logged. 15 | Task Log(string message); 16 | 17 | /// 18 | /// Logs the specified message. 19 | /// 20 | /// The message to be logged. 21 | /// Exception 22 | Task Log(string message, Exception exception); 23 | } 24 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/System/ISystemService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace GamerVII.Launcher.Services.System; 4 | 5 | public interface ISystemService 6 | { 7 | ulong GetMaxAvailableRam(); 8 | Task GetInstallationDirectory(); 9 | Task GetGamePath(); 10 | Task SetInstallationDirectory(string appDirectory); 11 | } 12 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Services/System/SystemService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | using System.Threading.Tasks; 7 | using GamerVII.Launcher.Services.LocalStorage; 8 | using Splat; 9 | 10 | namespace GamerVII.Launcher.Services.System; 11 | 12 | public class SystemService : ISystemService 13 | { 14 | private readonly ILocalStorageService _localStorage; 15 | 16 | public SystemService(ILocalStorageService? localStorage = null) 17 | { 18 | _localStorage = localStorage 19 | ?? Locator.Current.GetService() 20 | ?? throw new Exception($"{nameof(ILocalStorageService)} not registered!"); 21 | } 22 | 23 | [DllImport("kernel32.dll", SetLastError = true)] 24 | [return: MarshalAs(UnmanagedType.Bool)] 25 | static extern bool GetPhysicallyInstalledSystemMemory(out ulong totalMemoryInKb); 26 | 27 | public ulong GetMaxAvailableRam() 28 | { 29 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 30 | { 31 | if (GetPhysicallyInstalledSystemMemory(out var totalMemoryInKb)) 32 | { 33 | return totalMemoryInKb / 1024; 34 | } 35 | } 36 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 37 | { 38 | return Convert.ToUInt64(GetUnixAvailableRam()); 39 | } 40 | 41 | return 0; 42 | } 43 | 44 | public async Task GetInstallationDirectory() 45 | { 46 | 47 | var appDirectory = await _localStorage.GetAsync("InstallationPath"); 48 | 49 | if (!string.IsNullOrEmpty(appDirectory)) 50 | { 51 | return appDirectory; 52 | } 53 | 54 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 55 | { 56 | appDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 57 | } 58 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 59 | { 60 | appDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); 61 | } 62 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 63 | { 64 | appDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); 65 | } 66 | 67 | if (string.IsNullOrEmpty(appDirectory) || CanCreateDirectory(appDirectory) == false) 68 | { 69 | appDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? AppDomain.CurrentDomain.BaseDirectory; 70 | } 71 | 72 | await _localStorage.SetAsync("InstallationPath", appDirectory); 73 | 74 | return appDirectory; 75 | } 76 | 77 | public async Task GetGamePath() 78 | { 79 | return Path.GetFullPath(Path.Combine(await GetInstallationDirectory(), "gamervii-launcher")); 80 | } 81 | 82 | public async Task SetInstallationDirectory(string appDirectory) 83 | { 84 | await _localStorage.SetAsync("InstallationPath", appDirectory); 85 | } 86 | 87 | private static bool CanCreateDirectory(string path) 88 | { 89 | try 90 | { 91 | var tempDirectory = Path.Combine(path, Guid.NewGuid().ToString()); 92 | Directory.CreateDirectory(tempDirectory); 93 | Directory.Delete(tempDirectory); 94 | return true; 95 | } 96 | catch (UnauthorizedAccessException) 97 | { 98 | return false; 99 | } 100 | catch (Exception ex) 101 | { 102 | return false; 103 | } 104 | } 105 | 106 | 107 | private ulong GetUnixAvailableRam() 108 | { 109 | string? output; 110 | 111 | var info = new ProcessStartInfo("free -m") 112 | { 113 | FileName = "/bin/bash", 114 | Arguments = "-c \"free -m\"", 115 | RedirectStandardOutput = true 116 | }; 117 | 118 | using (var process = Process.Start(info)) 119 | { 120 | output = process?.StandardOutput.ReadToEnd(); 121 | } 122 | 123 | if (string.IsNullOrEmpty(output)) 124 | return 0; 125 | 126 | var lines = output.Split("\n"); 127 | var memory = lines[1].Split(" ", StringSplitOptions.RemoveEmptyEntries); 128 | 129 | return Convert.ToUInt64(memory[1]); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewLocator.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Controls.Templates; 3 | using GamerVII.Launcher.ViewModels.Base; 4 | using System; 5 | 6 | namespace GamerVII.Launcher 7 | { 8 | public class ViewLocator : IDataTemplate 9 | { 10 | public Control Build(object? data) 11 | { 12 | var name = data? 13 | .GetType().FullName! 14 | .Replace("ViewModel", "View") 15 | ?? string.Empty; 16 | 17 | var componentName = data?.GetType().FullName! 18 | .Replace("ViewModel", "View") 19 | .Replace("Views", "Views.Components") 20 | ?? string.Empty; 21 | 22 | var pageName = data?.GetType().FullName! 23 | .Replace("ViewModel", "View") 24 | .Replace("Views", "Views.Pages") 25 | ?? string.Empty; 26 | 27 | var type = (Type.GetType(name) 28 | ?? Type.GetType(componentName)) 29 | ?? Type.GetType(pageName); 30 | 31 | if (type != null) 32 | { 33 | return (Control)Activator.CreateInstance(type)!; 34 | } 35 | 36 | return new TextBlock { Text = "Not Found: " + name }; 37 | } 38 | 39 | public bool Match(object? data) 40 | { 41 | return data is ViewModelBase; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/Base/PageViewModelBase.cs: -------------------------------------------------------------------------------- 1 | namespace GamerVII.Launcher.ViewModels.Base; 2 | 3 | /// 4 | /// Base class for view models related to pages. 5 | /// 6 | public abstract class PageViewModelBase : ViewModelBase 7 | { 8 | 9 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/Base/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | namespace GamerVII.Launcher.ViewModels.Base; 4 | 5 | /// 6 | /// Base class for view models, derived from ReactiveObject. 7 | /// 8 | public class ViewModelBase : ReactiveObject 9 | { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/Pages/AddClientPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | using System.Reactive.Concurrency; 5 | using System.Reactive.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows.Input; 8 | using GamerVII.Launcher.Models.Client; 9 | using GamerVII.Launcher.Models.Enums; 10 | using GamerVII.Launcher.Services.GameLaunch; 11 | using GamerVII.Launcher.ViewModels.Base; 12 | using ReactiveUI; 13 | using Splat; 14 | 15 | namespace GamerVII.Launcher.ViewModels.Pages; 16 | 17 | public class AddClientPageViewModel : PageViewModelBase 18 | { 19 | /// 20 | /// Command to navigate to the main page. 21 | /// 22 | public ICommand? GoToMainPageCommand { get; set; } 23 | 24 | /// 25 | /// Command to add new client 26 | /// 27 | public ICommand? SaveClientCommand { get; set; } 28 | 29 | public IGameClient NewGameClient 30 | { 31 | get => _newGameClient; 32 | set => this.RaiseAndSetIfChanged(ref _newGameClient, value); 33 | } 34 | 35 | public ObservableCollection MinecraftVersions 36 | { 37 | get => _minecraftVersions; 38 | set => this.RaiseAndSetIfChanged(ref _minecraftVersions, value); 39 | } 40 | 41 | public IMinecraftVersion? SelectedVersion 42 | { 43 | get => _selectedVersion; 44 | set 45 | { 46 | this.RaiseAndSetIfChanged(ref _selectedVersion, value); 47 | 48 | if (SelectedVersion != null) 49 | { 50 | var newClient = new GameClient 51 | { 52 | Version = SelectedVersion.Version, 53 | Name = string.IsNullOrWhiteSpace(_newGameClient.Name) || FindVersion(_newGameClient.Name) != null 54 | ? SelectedVersion.Version 55 | : _newGameClient.Name, 56 | ModLoaderType = SelectedVersion.Version.Contains("Forge") 57 | ? ModLoaderType.Forge 58 | : ModLoaderType.Vanilla, 59 | Description = _newGameClient.Description 60 | }; 61 | 62 | NewGameClient = newClient; 63 | } 64 | } 65 | } 66 | 67 | public string? SearchText 68 | { 69 | get => _searchText; 70 | set => this.RaiseAndSetIfChanged(ref _searchText, value); 71 | } 72 | 73 | public bool IsBusy 74 | { 75 | get => _isBusy; 76 | set => this.RaiseAndSetIfChanged(ref _isBusy, value); 77 | } 78 | 79 | private IGameClient _newGameClient = new GameClient(); 80 | private ObservableCollection _minecraftVersions = new(); 81 | private IMinecraftVersion? _selectedVersion; 82 | private readonly IGameLaunchService _gameLaunchService; 83 | private string? _searchText; 84 | private bool _isBusy; 85 | 86 | /// 87 | /// Initializes a new instance of the ProfilePageViewModel class. 88 | /// 89 | public AddClientPageViewModel(IGameLaunchService? gameLaunchService = null) 90 | { 91 | _gameLaunchService = gameLaunchService 92 | ?? Locator.Current.GetService() 93 | ?? throw new Exception($"{nameof(IGameLaunchService)} not registered"); 94 | 95 | 96 | this.WhenAnyValue(x => x.SearchText) 97 | .Throttle(TimeSpan.FromMilliseconds(400)) 98 | .ObserveOn(RxApp.MainThreadScheduler) 99 | .Subscribe(DoSearch!); 100 | 101 | RxApp.MainThreadScheduler.Schedule(LoadData); 102 | } 103 | 104 | private async void LoadData() 105 | { 106 | await LoadVersions(); 107 | } 108 | 109 | private async Task LoadVersions() 110 | { 111 | var versions = await _gameLaunchService.GetAvailableVersions(); 112 | 113 | MinecraftVersions = new ObservableCollection(versions); 114 | } 115 | 116 | private async void DoSearch(string text) 117 | { 118 | IsBusy = true; 119 | MinecraftVersions.Clear(); 120 | 121 | if (!string.IsNullOrWhiteSpace(text)) 122 | { 123 | text = text.Replace(",", "."); 124 | 125 | var versions = await _gameLaunchService.GetAvailableVersions(); 126 | 127 | versions = versions.Where(c => c.Version.Contains(text)); 128 | 129 | await Task.Delay(500); 130 | MinecraftVersions = new ObservableCollection(versions); 131 | } 132 | else 133 | { 134 | await LoadVersions(); 135 | } 136 | 137 | IsBusy = false; 138 | } 139 | 140 | private IMinecraftVersion? FindVersion(string version) 141 | { 142 | return MinecraftVersions.FirstOrDefault(c => c.Version == version); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/Pages/AuthPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | using GamerVII.Launcher.Models.Users; 4 | using GamerVII.Launcher.Services.Auth; 5 | using GamerVII.Launcher.ViewModels.Base; 6 | using ReactiveUI; 7 | using Splat; 8 | 9 | namespace GamerVII.Launcher.ViewModels.Pages; 10 | 11 | /// 12 | /// View model class for the authentication page, derived from PageViewModelBase. 13 | /// 14 | public class AuthPageViewModel : PageViewModelBase 15 | { 16 | /// 17 | /// Delegate for handling the authorization event. 18 | /// 19 | /// User. 20 | public delegate void AuthorizeHandler(IUser user); 21 | 22 | /// 23 | /// Event raised when the authorization process is completed. 24 | /// 25 | public event AuthorizeHandler? Authorized; 26 | 27 | /// 28 | /// Gets or sets the login string for authentication. 29 | /// 30 | public string Login 31 | { 32 | get => _login; 33 | set => this.RaiseAndSetIfChanged(ref _login, value); 34 | } 35 | 36 | /// 37 | /// Gets or sets the password string for authentication. 38 | /// 39 | public string Password 40 | { 41 | get => _password; 42 | set => this.RaiseAndSetIfChanged(ref _password, value); 43 | } 44 | 45 | /// 46 | /// Gets or sets a value indicating whether the user is currently being authorized. 47 | /// 48 | public bool IsAuthorizing 49 | { 50 | get => _isAuthorizing; 51 | set => this.RaiseAndSetIfChanged(ref _isAuthorizing, value); 52 | } 53 | 54 | /// 55 | /// Command that triggers the login process. 56 | /// 57 | public ICommand OnLoginCommand { get; } 58 | 59 | private readonly IAuthService _authService; 60 | private string _login = string.Empty; 61 | private string _password = string.Empty; 62 | private bool _isAuthorizing; 63 | 64 | /// 65 | /// Initializes a new instance of the AuthPageViewModel class. 66 | /// 67 | /// An optional IAuthService implementation for user authentication. 68 | public AuthPageViewModel(IAuthService? authService = null) 69 | { 70 | _authService = authService 71 | ?? Locator.Current.GetService() 72 | ?? throw new Exception("AuthService not registered"); 73 | 74 | var canLaunch = this.WhenAnyValue( 75 | x => x.Login, x => x.Password, 76 | (login, password) => 77 | !string.IsNullOrWhiteSpace(login) 78 | // && !string.IsNullOrWhiteSpace(password) 79 | ); 80 | 81 | OnLoginCommand = ReactiveCommand.Create(OnLogin, canLaunch); 82 | } 83 | 84 | private async void OnLogin() 85 | { 86 | IsAuthorizing = true; 87 | 88 | var user = await _authService.OnLogin(Login, Password); 89 | 90 | if (user.IsLogin) 91 | { 92 | Authorized?.Invoke(user); 93 | } 94 | 95 | IsAuthorizing = false; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/Pages/ModsPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | using GamerVII.Launcher.Models.Client; 3 | using GamerVII.Launcher.ViewModels.Base; 4 | using ReactiveUI; 5 | 6 | namespace GamerVII.Launcher.ViewModels.Pages; 7 | 8 | /// 9 | /// View model class for the profile page, derived from PageViewModelBase. 10 | /// 11 | public class ModsPageViewModel : PageViewModelBase 12 | { 13 | /// 14 | /// Command to navigate to the main page. 15 | /// 16 | public ICommand GoToMainPageCommand { get; set; } 17 | 18 | public IGameClient SelectClient 19 | { 20 | get => _selectedClient; 21 | set => this.RaiseAndSetIfChanged(ref _selectedClient, value); 22 | } 23 | 24 | private IGameClient _selectedClient; 25 | 26 | /// 27 | /// Initializes a new instance of the ProfilePageViewModel class. 28 | /// 29 | public ModsPageViewModel() 30 | { 31 | // Add any initialization logic or data loading here if required. 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/Pages/ProfilePageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Windows.Input; 3 | using GamerVII.Launcher.Models.Users; 4 | using GamerVII.Launcher.ViewModels.Base; 5 | using ReactiveUI; 6 | 7 | namespace GamerVII.Launcher.ViewModels.Pages; 8 | 9 | /// 10 | /// View model class for the profile page, derived from PageViewModelBase. 11 | /// 12 | public class ProfilePageViewModel : PageViewModelBase 13 | { 14 | 15 | /// 16 | /// Command to navigate to the main page. 17 | /// 18 | public ICommand GoToMainPageCommand { get; set; } 19 | public ICommand OpenLinkCommand { get; set; } 20 | 21 | public IUser User 22 | { 23 | get => _user; 24 | set => this.RaiseAndSetIfChanged(ref _user, value); 25 | } 26 | 27 | private IUser _user; 28 | 29 | /// 30 | /// Initializes a new instance of the ProfilePageViewModel class. 31 | /// 32 | public ProfilePageViewModel() 33 | { 34 | OpenLinkCommand = ReactiveCommand.Create((string url) => OpenLink(url)); 35 | } 36 | 37 | 38 | private void OpenLink(string url) 39 | { 40 | Process.Start(new ProcessStartInfo 41 | { 42 | FileName = url, 43 | UseShellExecute = true 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/Pages/SettingsPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reactive.Concurrency; 4 | using System.Threading.Tasks; 5 | using System.Windows.Input; 6 | using Avalonia; 7 | using Avalonia.Controls.ApplicationLifetimes; 8 | using Avalonia.Platform.Storage; 9 | using GamerVII.Launcher.Models.Users; 10 | using GamerVII.Launcher.Services.GameLaunch; 11 | using GamerVII.Launcher.Services.System; 12 | using GamerVII.Launcher.ViewModels.Base; 13 | using GamerVII.Launcher.Views; 14 | using ReactiveUI; 15 | using Splat; 16 | 17 | namespace GamerVII.Launcher.ViewModels.Pages; 18 | 19 | /// 20 | /// View model class for the client settings page, derived from PageViewModelBase. 21 | /// 22 | public class SettingsPageViewModel : PageViewModelBase 23 | { 24 | private readonly IGameLaunchService? _gameLaunchService; 25 | 26 | 27 | public int MemorySize 28 | { 29 | get => _memorySize; 30 | set 31 | { 32 | if (value % 8 == 0) 33 | { 34 | this.RaiseAndSetIfChanged(ref _memorySize, value); 35 | } 36 | } 37 | } 38 | public int MaxMemorySize 39 | { 40 | get => _maxMemorySize; 41 | set => this.RaiseAndSetIfChanged(ref _maxMemorySize, value); 42 | } 43 | public int WindowWidth 44 | { 45 | get => _windowWidth; 46 | set => this.RaiseAndSetIfChanged(ref _windowWidth, value); 47 | } 48 | public int WindowHeight 49 | { 50 | get => _windowHeight; 51 | set => this.RaiseAndSetIfChanged(ref _windowHeight, value); 52 | } 53 | 54 | public bool IsFullScreen 55 | { 56 | get => _isFullScreen; 57 | set => this.RaiseAndSetIfChanged(ref _isFullScreen, value); 58 | } 59 | public IUser? User 60 | { 61 | get => _user; 62 | set => this.RaiseAndSetIfChanged(ref _user, value); 63 | } 64 | public string InstallationFolderPath 65 | { 66 | get => _installationFolderPath; 67 | set => this.RaiseAndSetIfChanged(ref _installationFolderPath, value); 68 | } 69 | 70 | 71 | private int _memorySize = 1024; 72 | private int _maxMemorySize = 1024; 73 | private int _windowWidth = 900; 74 | private int _windowHeight = 600; 75 | private bool _isFullScreen; 76 | private IUser? _user; 77 | private string _installationFolderPath = string.Empty; 78 | 79 | private readonly ISystemService _systemService; 80 | /// 81 | /// Command to navigate to the main page. 82 | /// 83 | public ICommand? GoToMainPageCommand { get; set; } 84 | public ICommand SelectFolderCommand { get; } 85 | 86 | 87 | public SettingsPageViewModel(ISystemService? systemService = null, IGameLaunchService? gameLaunchService = null) 88 | { 89 | _gameLaunchService = gameLaunchService 90 | ?? Locator.Current.GetService() 91 | ?? throw new Exception($"{nameof(IGameLaunchService)} not registered"); 92 | 93 | _systemService = systemService 94 | ?? Locator.Current.GetService() 95 | ?? throw new Exception($"{nameof(ISystemService)} not registered"); 96 | 97 | MaxMemorySize = Convert.ToInt32(_systemService.GetMaxAvailableRam()); 98 | 99 | SelectFolderCommand = ReactiveCommand.CreateFromTask(OnSelectFolder); 100 | 101 | RxApp.MainThreadScheduler.Schedule(LoadData); 102 | } 103 | 104 | 105 | private async void LoadData() 106 | { 107 | InstallationFolderPath = await _systemService.GetGamePath(); 108 | } 109 | 110 | private async Task OnSelectFolder() 111 | { 112 | var options = new FolderPickerOpenOptions() 113 | { 114 | Title = "Выберите папку для установки", 115 | AllowMultiple = false 116 | }; 117 | 118 | var appLifetime = Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime; 119 | 120 | 121 | if (appLifetime?.MainWindow is MainWindow mainWindow) 122 | { 123 | var result = await mainWindow.StorageProvider.OpenFolderPickerAsync(options); 124 | 125 | if (result.Any()) 126 | { 127 | 128 | await _systemService.SetInstallationDirectory(InstallationFolderPath); 129 | 130 | InstallationFolderPath = await _systemService.GetGamePath(); 131 | 132 | if (_gameLaunchService is GameLaunchService launchService) 133 | { 134 | await launchService.InitMinecraftLauncher(); 135 | } 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/ServersListViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using GamerVII.Launcher.Models.Client; 4 | using GamerVII.Launcher.ViewModels.Base; 5 | using ReactiveUI; 6 | using Splat; 7 | using System.Collections.ObjectModel; 8 | using System.Linq; 9 | using System.Windows.Input; 10 | using DynamicData; 11 | using GamerVII.Launcher.Services.Client; 12 | using GamerVII.Launcher.Services.LocalStorage; 13 | 14 | namespace GamerVII.Launcher.ViewModels; 15 | 16 | /// 17 | /// View model class for the list of game servers, derived from ViewModelBase. 18 | /// 19 | public class ServersListViewModel : ViewModelBase 20 | { 21 | public delegate void SelectedServerHandler(); 22 | public event SelectedServerHandler? SelectedServerChanged; 23 | 24 | public ObservableCollection GameClients 25 | { 26 | get => _gameClients; 27 | set => this.RaiseAndSetIfChanged(ref _gameClients, value); 28 | } 29 | 30 | public IGameClient? SelectedClient 31 | { 32 | get => _selectedClient; 33 | set 34 | { 35 | this.RaiseAndSetIfChanged(ref _selectedClient, value); 36 | SelectedServerChanged?.Invoke(); 37 | } 38 | } 39 | public ICommand AddClientCommand { get; set; } = null!; 40 | public ICommand RemoveClientCommand { get; set; } = null!; 41 | 42 | private readonly IGameClientService _gameClientService; 43 | private readonly ILocalStorageService _localStorageService; 44 | 45 | private ObservableCollection _gameClients = null!; 46 | private IGameClient? _selectedClient; 47 | 48 | public ServersListViewModel( 49 | IGameClientService? gameClientService = null, 50 | ILocalStorageService? localStorageService = null 51 | ) 52 | { 53 | _localStorageService = localStorageService 54 | ?? Locator.Current.GetService() 55 | ?? throw new Exception($"{nameof(ILocalStorageService)} not registered"); 56 | 57 | _gameClientService = gameClientService 58 | ?? Locator.Current.GetService() 59 | ?? throw new Exception($"{nameof(IGameClientService)} not registered"); 60 | 61 | RemoveClientCommand = 62 | ReactiveCommand.CreateFromTask(async (IGameClient gameClient) => RemoveClient(gameClient)); 63 | 64 | LoadData(); 65 | } 66 | 67 | private void RemoveClient(IGameClient gameClient) 68 | { 69 | _gameClients.Remove(gameClient); 70 | 71 | _localStorageService.SetAsync("Clients", _gameClients); 72 | 73 | } 74 | 75 | private async void LoadData() 76 | { 77 | var clients = await _gameClientService.GetClientsAsync(); 78 | 79 | GameClients = new ObservableCollection(clients); 80 | 81 | if (await _localStorageService.GetAsync>("Clients") is { } localClients) 82 | { 83 | GameClients.AddRange(localClients); 84 | } 85 | 86 | SelectedClient = GameClients.FirstOrDefault(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/ViewModels/SidebarViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | using GamerVII.Launcher.ViewModels.Base; 3 | 4 | namespace GamerVII.Launcher.ViewModels; 5 | 6 | /// 7 | /// View model class for the sidebar, derived from ViewModelBase. 8 | /// 9 | public class SidebarViewModel : ViewModelBase 10 | { 11 | /// 12 | /// Gets the view model for the list of game servers. 13 | /// 14 | public ServersListViewModel ServersListViewModel { get; } 15 | 16 | /// 17 | /// Command to open the profile page. 18 | /// 19 | public ICommand OpenProfilePageCommand { get; set; } 20 | 21 | /// 22 | /// Command to execute the logout operation. 23 | /// 24 | public ICommand LogoutCommand { get; set; } 25 | 26 | /// 27 | /// Initializes a new instance of the SidebarViewModel class. 28 | /// 29 | public SidebarViewModel() 30 | { 31 | // Initialize the ServersListViewModel to handle game servers data. 32 | ServersListViewModel = new ServersListViewModel(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/ButtonControl.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 41 | 42 | 44 | 45 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 58 | 62 | 63 | 84 | 85 | 87 | 88 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 124 | 125 | 127 | 129 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 198 | 199 | 202 | 203 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/ButtonControl.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | using Avalonia; 3 | using Avalonia.Controls; 4 | using Avalonia.Controls.Primitives; 5 | 6 | namespace GamerVII.Launcher.Views.Components; 7 | 8 | public class ButtonControl : TemplatedControl 9 | { 10 | 11 | public static readonly StyledProperty IconPathProperty = AvaloniaProperty.Register( 12 | nameof(IconPath), "/Assets/document.svg"); 13 | 14 | public static readonly StyledProperty TextProperty = AvaloniaProperty.Register( 15 | nameof(Text), "КНОПКА"); 16 | 17 | public static readonly StyledProperty CommandProperty = AvaloniaProperty.Register( 18 | nameof(Command)); 19 | 20 | public static readonly StyledProperty CommandParameterProperty = AvaloniaProperty.Register( 21 | nameof(CommandParameter)); 22 | 23 | public object CommandParameter 24 | { 25 | get => GetValue(CommandParameterProperty); 26 | set => SetValue(CommandParameterProperty, value); 27 | } 28 | 29 | public string IconPath 30 | { 31 | get => GetValue(IconPathProperty); 32 | set => SetValue(IconPathProperty, value); 33 | } 34 | 35 | public string Text 36 | { 37 | get => GetValue(TextProperty); 38 | set => SetValue(TextProperty, value); 39 | } 40 | 41 | public ICommand Command 42 | { 43 | get => GetValue(CommandProperty); 44 | set => SetValue(CommandProperty, value); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/DownloadStatusComponent.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/DownloadStatusComponent.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Primitives; 4 | 5 | namespace GamerVII.Launcher.Views.Components; 6 | 7 | public class DownloadStatusComponent : TemplatedControl 8 | { 9 | 10 | public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register( 11 | nameof(Title), "Заголовок"); 12 | 13 | public static readonly StyledProperty DescriptionProperty = AvaloniaProperty.Register( 14 | nameof(Description), "Описание"); 15 | 16 | public static readonly StyledProperty PercentageProperty = AvaloniaProperty.Register( 17 | nameof(Percentage), "100"); 18 | 19 | public string Percentage 20 | { 21 | get => GetValue(PercentageProperty); 22 | set => SetValue(PercentageProperty, value); 23 | } 24 | 25 | public string Description 26 | { 27 | get => GetValue(DescriptionProperty); 28 | set => SetValue(DescriptionProperty, value); 29 | } 30 | public string Title 31 | { 32 | get => GetValue(TitleProperty); 33 | set => SetValue(TitleProperty, value); 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/FolderPickerControl.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 9 | 10 | 45 | 46 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/FolderPickerControl.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using System.Windows.Input; 4 | using Avalonia; 5 | using Avalonia.Controls; 6 | using Avalonia.Controls.ApplicationLifetimes; 7 | using Avalonia.Controls.Primitives; 8 | using Avalonia.Platform.Storage; 9 | using ReactiveUI; 10 | 11 | namespace GamerVII.Launcher.Views.Components; 12 | 13 | public class FolderPickerControl : TemplatedControl 14 | { 15 | public static readonly StyledProperty SelectFolderCommandProperty = 16 | AvaloniaProperty.Register( 17 | nameof(SelectFolderCommand)); 18 | 19 | public static readonly StyledProperty SelectedFolderPathProperty = 20 | AvaloniaProperty.Register( 21 | nameof(SelectedFolderPath)); 22 | 23 | public string SelectedFolderPath 24 | { 25 | get => GetValue(SelectedFolderPathProperty); 26 | set => SetValue(SelectedFolderPathProperty, value); 27 | } 28 | public ICommand SelectFolderCommand 29 | { 30 | get => GetValue(SelectFolderCommandProperty); 31 | set => SetValue(SelectFolderCommandProperty, value); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/LogoutButton.axaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/LogoutButton.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace GamerVII.Launcher.Views.Components; 5 | 6 | public partial class LogoutButton : UserControl 7 | { 8 | public LogoutButton() 9 | { 10 | InitializeComponent(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/ServerContent.axaml: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/ServerContent.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace GamerVII.Launcher.Views.Components; 5 | 6 | public partial class ServerContent : UserControl 7 | { 8 | public ServerContent() 9 | { 10 | InitializeComponent(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/ServersListView.axaml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | 37 | 41 | 44 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/ServersListView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace GamerVII.Launcher.Views.Components; 6 | 7 | public partial class ServersListView : UserControl 8 | { 9 | public ServersListView() 10 | { 11 | InitializeComponent(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/SidebarView.axaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 36 | 37 | 38 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Components/SidebarView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace GamerVII.Launcher.Views.Components; 4 | 5 | public partial class SidebarView : UserControl 6 | { 7 | 8 | 9 | public SidebarView() 10 | { 11 | InitializeComponent(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Converters/IsNotNullConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | using Avalonia.Markup.Xaml; 5 | 6 | namespace GamerVII.Launcher.Views.Converters; 7 | 8 | public class IsNotNullConverter : MarkupExtension, IValueConverter 9 | { 10 | public override object ProvideValue(IServiceProvider serviceProvider) => this; 11 | 12 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 13 | { 14 | return value is not null; 15 | } 16 | 17 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => null; 18 | } 19 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Converters/ListNotEmptyConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using Avalonia.Data.Converters; 6 | using Avalonia.Markup.Xaml; 7 | 8 | namespace GamerVII.Launcher.Views.Converters; 9 | 10 | public class ListNotEmptyConverter : MarkupExtension, IValueConverter 11 | { 12 | public override object ProvideValue(IServiceProvider serviceProvider) => this; 13 | 14 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 15 | { 16 | if (value is IEnumerable enumerable) 17 | { 18 | return enumerable.Any(); 19 | } 20 | 21 | return true; 22 | } 23 | 24 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => null; 25 | } 26 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Converters/ReleaseDateFromMinecraftVersionConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | using Avalonia.Markup.Xaml; 5 | using GamerVII.Launcher.Models.Client; 6 | 7 | namespace GamerVII.Launcher.Views.Converters; 8 | 9 | public class ReleaseDateFromMinecraftVersionConverter : MarkupExtension, IValueConverter 10 | { 11 | public override object ProvideValue(IServiceProvider serviceProvider) => this; 12 | 13 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 14 | { 15 | 16 | if (value is MinecraftVersion minecraftVersion) 17 | { 18 | return minecraftVersion.MVersion.ReleaseTime?.ToString("dd.MM.yyyy в HH:mm"); 19 | } 20 | 21 | return string.Empty; 22 | 23 | } 24 | 25 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) 26 | { 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Converters/ReverseBoolValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | using Avalonia.Markup.Xaml; 5 | 6 | namespace GamerVII.Launcher.Views.Converters; 7 | 8 | public class ReverseBoolValueConverter : MarkupExtension, IValueConverter 9 | { 10 | public override object ProvideValue(IServiceProvider serviceProvider) => this; 11 | 12 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 13 | { 14 | if (value is bool booleanValue) 15 | { 16 | return !booleanValue; 17 | } 18 | 19 | return value; 20 | } 21 | 22 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => value; 23 | } 24 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 50 | 51 | 53 | 54 | 55 | 56 | 57 | 58 | 60 | 63 | 64 | 65 | 69 | 70 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 113 | 114 | 117 | 118 | 119 | 120 | 124 | 125 | 126 | 129 | 130 | 135 | 136 | 138 | 139 | 143 | 144 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 162 | 163 | 168 | 169 | 170 | 174 | 175 | 179 | 180 | 184 | 185 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Input; 3 | 4 | namespace GamerVII.Launcher.Views 5 | { 6 | public partial class MainWindow : Window 7 | { 8 | public MainWindow() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | protected override void OnPointerPressed(PointerPressedEventArgs e) 14 | { 15 | BeginMoveDrag(e); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/AddClientPageView.axaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 15 | 16 | 17 | 18 | 19 | 21 | 24 | 25 | 26 | 27 | 28 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 50 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 69 | 70 | 71 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 87 | 91 | 92 | 93 | 94 | 99 | 100 | 104 | 109 | 110 | 111 | 112 | 113 | 117 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 135 | 136 | 137 | 138 | 139 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/AddClientPageView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace GamerVII.Launcher.Views.Pages; 5 | 6 | public partial class AddClientPageView : UserControl 7 | { 8 | public AddClientPageView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/AuthPageView.axaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/AuthPageView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace GamerVII.Launcher.Views.Pages; 5 | 6 | public partial class AuthPageView : UserControl 7 | { 8 | public AuthPageView() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | private void InitializeComponent() 14 | { 15 | AvaloniaXamlLoader.Load(this); 16 | } 17 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/ModsPageView.axaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 14 | 15 | 17 | 18 | 23 | 24 | 25 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/ModsPageView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace GamerVII.Launcher.Views.Pages; 5 | 6 | public partial class ModsPageView : UserControl 7 | { 8 | public ModsPageView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/ProfilePageView.axaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 56 | 57 | 58 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 73 | 74 | 75 | 76 | 77 | 78 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 95 | 96 | 97 | 103 | 104 | 105 | 108 | 109 | 114 | 115 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/ProfilePageView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace GamerVII.Launcher.Views.Pages; 5 | 6 | public partial class ProfilePageView : UserControl 7 | { 8 | public ProfilePageView() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | private void InitializeComponent() 14 | { 15 | AvaloniaXamlLoader.Load(this); 16 | } 17 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/SettingsPageView.axaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 22 | 23 | 28 | 29 | 30 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 43 | 45 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 59 | 60 | 63 | 66 | 67 | 68 | 69 | 70 | 71 | 73 | 74 | 75 | 76 | 78 | 79 | 80 | 82 | 84 | 85 | 86 | 87 | 88 | 90 | 91 | 92 | 93 | 94 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/Views/Pages/SettingsPageView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace GamerVII.Launcher.Views.Pages; 5 | 6 | public partial class SettingsPageView : UserControl 7 | { 8 | public SettingsPageView() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | private void InitializeComponent() 14 | { 15 | AvaloniaXamlLoader.Load(this); 16 | } 17 | } -------------------------------------------------------------------------------- /src/GamerVII.Launcher/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/GamerVII.Launcher/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamerVII-NET/minecraft-vanilla-launcher/00a0c21ea532e2bfb42f5adcb475fc87508617b2/src/GamerVII.Launcher/icon.ico -------------------------------------------------------------------------------- /tests/GamerVII.Launcher.Tests/GameClientsTests.cs: -------------------------------------------------------------------------------- 1 | using GamerVII.Launcher.Extensions; 2 | using GamerVII.Launcher.Models.Client; 3 | using GamerVII.Launcher.Models.Enums; 4 | using GamerVII.Launcher.Services.Client; 5 | using GamerVII.Launcher.Services.GameLaunch; 6 | using GamerVII.Launcher.ViewModels; 7 | using GamerVII.Launcher.ViewModels.Pages; 8 | using ReactiveUI; 9 | using Splat; 10 | 11 | namespace GamerVII.Launcher.Tests; 12 | 13 | public class GameClientsTests 14 | { 15 | private MainWindowViewModel _mainViewModel; 16 | private AddClientPageViewModel _addClientViewModel; 17 | private IGameLaunchService _gameLaunchService; 18 | 19 | [SetUp] 20 | public void Setup() 21 | { 22 | ServiceRegister.RegisterServices(); 23 | 24 | _mainViewModel = new MainWindowViewModel(); 25 | 26 | 27 | _addClientViewModel = _mainViewModel.GetPageViewModelByType() as AddClientPageViewModel 28 | ?? throw new Exception($"{nameof(AddClientPageViewModel)} not found"); 29 | 30 | 31 | _gameLaunchService = Locator.Current.GetService() ?? 32 | throw new Exception($"{nameof(IGameLaunchService)} not found"); 33 | } 34 | 35 | [Test, Order(1)] 36 | public async Task GetRandomMinecraftVersionTest() 37 | { 38 | var randomMinecraftVersion = await GetRandomVMinecraftVersion(); 39 | 40 | Assert.That(randomMinecraftVersion, Is.Not.Null); 41 | } 42 | 43 | private async Task GetRandomVMinecraftVersion() 44 | { 45 | Random random = new(); 46 | 47 | var versions = (await _gameLaunchService.GetAvailableVersions()).ToList(); 48 | 49 | var randomMinecraftVersion = versions[random.Next(0, versions.Count - 1)]; 50 | return randomMinecraftVersion; 51 | } 52 | 53 | [Test, Order(2)] 54 | public async Task CanCreateClientTest() 55 | { 56 | await CreateMinecraftClient(); 57 | 58 | var canCreate = _addClientViewModel.SaveClientCommand.CanExecute(_addClientViewModel.NewGameClient); 59 | 60 | Assert.That(canCreate, Is.True); 61 | } 62 | 63 | [Test, Order(3)] 64 | public async Task CreateClientTest() 65 | { 66 | 67 | await CreateMinecraftClient(); 68 | 69 | _addClientViewModel.SaveClientCommand.Execute(null); 70 | 71 | Assert.That(_mainViewModel.SidebarViewModel.ServersListViewModel.GameClients.Last(), Is.EqualTo(_addClientViewModel.NewGameClient)); 72 | } 73 | 74 | private async Task CreateMinecraftClient() 75 | { 76 | var randomMinecraftVersion = await GetRandomVMinecraftVersion(); 77 | 78 | _addClientViewModel.NewGameClient = new GameClient 79 | { 80 | Version = randomMinecraftVersion.Version, 81 | Name = "Server", 82 | Description = "Description for server", 83 | InstallationVersion = randomMinecraftVersion.Version, 84 | ModLoaderType = ModLoaderType.Vanilla, 85 | Image = null 86 | }; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/GamerVII.Launcher.Tests/GamerVII.Launcher.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/GamerVII.Launcher.Tests/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using NUnit.Framework; 2 | -------------------------------------------------------------------------------- /tests/GamerVII.Launcher.Tests/LoginTests.cs: -------------------------------------------------------------------------------- 1 | using GamerVII.Launcher.Extensions; 2 | using GamerVII.Launcher.Models.Users; 3 | using GamerVII.Launcher.Services.LocalStorage; 4 | using GamerVII.Launcher.ViewModels; 5 | using GamerVII.Launcher.ViewModels.Pages; 6 | 7 | namespace GamerVII.Launcher.Tests; 8 | 9 | public class Tests 10 | { 11 | private AuthPageViewModel _authPageViewModel; 12 | private MainWindowViewModel _mainViewModel; 13 | private LocalStorageService _storageService; 14 | private bool _isAuthorized; 15 | 16 | 17 | [SetUp] 18 | public void Setup() 19 | { 20 | 21 | ServiceRegister.RegisterServices(); 22 | 23 | _authPageViewModel = new AuthPageViewModel 24 | { 25 | Login = "GamerVII", 26 | Password = "password" 27 | }; 28 | 29 | _mainViewModel = new MainWindowViewModel(); 30 | 31 | _authPageViewModel.Authorized += async user => 32 | { 33 | _isAuthorized = user.IsLogin; 34 | 35 | await _storageService.SetAsync("User", user); 36 | }; 37 | 38 | _storageService = new LocalStorageService(); 39 | 40 | } 41 | 42 | [Test, Order(1)] 43 | public void CanExecuteAuthTest() 44 | { 45 | Assert.That(_authPageViewModel.OnLoginCommand.CanExecute(null), Is.True); 46 | } 47 | 48 | [Test, Order(2)] 49 | public void AuthTest() 50 | { 51 | _authPageViewModel.OnLoginCommand.Execute(null); 52 | 53 | Assert.That(_isAuthorized, Is.True); 54 | } 55 | 56 | [Test, Order(3)] 57 | public async Task UserIsSavedTest() 58 | { 59 | var user = await _storageService.GetAsync("User"); 60 | 61 | Assert.That(user, Is.Not.Null); 62 | } 63 | 64 | [Test, Order(4)] 65 | public async Task SavedUserCanLogInTest() 66 | { 67 | var user = await _storageService.GetAsync("User"); 68 | 69 | if (user != null) 70 | { 71 | _authPageViewModel = new AuthPageViewModel 72 | { 73 | Login = user.Login, 74 | Password = user.Password 75 | }; 76 | 77 | Assert.Multiple(() => 78 | { 79 | Assert.That(_authPageViewModel.OnLoginCommand.CanExecute(null), Is.True); 80 | 81 | _authPageViewModel.OnLoginCommand.Execute(null); 82 | 83 | Assert.That(_isAuthorized, Is.True); 84 | }); 85 | 86 | } 87 | 88 | 89 | Assert.That(user, Is.Not.Null); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tests/GamerVII.Launcher.Tests/SettingsViewModelTests.cs: -------------------------------------------------------------------------------- 1 | using GamerVII.Launcher.Extensions; 2 | using GamerVII.Launcher.ViewModels; 3 | using GamerVII.Launcher.ViewModels.Pages; 4 | using ReactiveUI; 5 | 6 | namespace GamerVII.Launcher.Tests; 7 | 8 | public class SettingsTests 9 | { 10 | private MainWindowViewModel _mainViewModel; 11 | private SettingsPageViewModel _settingsViewModel; 12 | 13 | [SetUp] 14 | public void Setup() 15 | { 16 | ServiceRegister.RegisterServices(); 17 | 18 | _mainViewModel = new MainWindowViewModel(); 19 | 20 | _settingsViewModel = _mainViewModel.GetPageViewModelByType() as SettingsPageViewModel 21 | ?? throw new Exception($"{nameof(SettingsPageViewModel)} not found"); 22 | 23 | _settingsViewModel.GoToMainPageCommand ??= ReactiveCommand.CreateFromTask(_mainViewModel.SaveSettings); 24 | } 25 | 26 | [Test] 27 | public void DefaultWindowNotEmptyTest() 28 | { 29 | _mainViewModel.OpenPage(); 30 | 31 | Assert.That(_mainViewModel.CurrentPage, Is.Not.Null); 32 | } 33 | 34 | [Test] 35 | public void ResetPageEmptyTest() 36 | { 37 | _mainViewModel.ResetPage(); 38 | 39 | Assert.That(_mainViewModel.CurrentPage, Is.Null); 40 | } 41 | 42 | [Test] 43 | public void CheckDefaultDataSettingsTest() 44 | { 45 | Assert.Multiple(() => 46 | { 47 | Assert.That(_settingsViewModel, Is.Not.Null); 48 | Assert.That(_settingsViewModel.MemorySize, Is.Not.Zero); 49 | Assert.That(_settingsViewModel.WindowWidth, Is.Not.Zero); 50 | Assert.That(_settingsViewModel.WindowHeight, Is.Not.Zero); 51 | }); 52 | } 53 | 54 | [Test] 55 | public void SaveSettingsTest() 56 | { 57 | _settingsViewModel.WindowWidth = 100; 58 | _settingsViewModel.WindowHeight = 100; 59 | _settingsViewModel.MemorySize = 256; 60 | 61 | _settingsViewModel.GoToMainPageCommand?.Execute(null); 62 | 63 | Assert.Multiple(() => 64 | { 65 | Assert.That(_settingsViewModel.WindowWidth, Is.EqualTo(100)); 66 | Assert.That(_settingsViewModel.WindowHeight, Is.EqualTo(100)); 67 | Assert.That(_settingsViewModel.MemorySize, Is.EqualTo(256)); 68 | }); 69 | } 70 | } 71 | --------------------------------------------------------------------------------