From b0d09e5f351a3d00e44a6af2ca9f292cea9e3b9c Mon Sep 17 00:00:00 2001 From: vectorluo Date: Fri, 22 Sep 2023 11:00:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 362 + README.md | 70 + lol-assist.sln | 44 + src/LOL.Assist.App/App.xaml | 16 + src/LOL.Assist.App/App.xaml.cs | 60 + src/LOL.Assist.App/AssemblyInfo.cs | 10 + src/LOL.Assist.App/Global.cs | 49 + src/LOL.Assist.App/LOL.Assist.App.csproj | 52 + src/LOL.Assist.App/Model/HeroRuneGroup.cs | 20 + src/LOL.Assist.App/Model/RuneGroup.cs | 51 + .../Resources/Position_Challenger-Bot.png | Bin 0 -> 6743 bytes .../Resources/Position_Challenger-Jungle.png | Bin 0 -> 12009 bytes .../Resources/Position_Challenger-Mid.png | Bin 0 -> 7731 bytes .../Resources/Position_Challenger-Support.png | Bin 0 -> 8091 bytes .../Resources/Position_Challenger-Top.png | Bin 0 -> 6732 bytes .../Resources/Resources.Designer.cs | 113 + src/LOL.Assist.App/Resources/Resources.resx | 136 + .../ViewModels/RunePopupViewModel.cs | 204 + .../ViewModels/RuneViewModel.cs | 91 + .../ViewModels/SelectHeroViewModel.cs | 56 + .../ViewModels/SettingViewModel.cs | 436 + .../Views/Controls/DelayTime.xaml | 22 + .../Views/Controls/DelayTime.xaml.cs | 53 + .../Views/Controls/HeroControl.xaml | 27 + .../Views/Controls/HeroControl.xaml.cs | 85 + src/LOL.Assist.App/Views/MainWindow.xaml | 79 + src/LOL.Assist.App/Views/MainWindow.xaml.cs | 169 + src/LOL.Assist.App/Views/Pages/RunePage.xaml | 167 + .../Views/Pages/RunePage.xaml.cs | 82 + .../Views/Pages/SettingPage.xaml | 224 + .../Views/Pages/SettingPage.xaml.cs | 70 + src/LOL.Assist.App/Views/RunePopupWindow.xaml | 371 + .../Views/RunePopupWindow.xaml.cs | 150 + .../Views/SelectHeroWindow.xaml | 112 + .../Views/SelectHeroWindow.xaml.cs | 57 + src/LOL.Assist.App/build.cmd | 6 + src/LOL.Assist.Core/DbModels/Config.cs | 26 + src/LOL.Assist.Core/DbModels/HeroRune.cs | 36 + src/LOL.Assist.Core/DbModels/SelectHero.cs | 40 + src/LOL.Assist.Core/Enums/ConfigKeyEnum.cs | 37 + .../Enums/SelectSessionEnum.cs | 21 + .../Enums/SubscribeEventUri.cs | 74 + src/LOL.Assist.Core/IServices/IDbService.cs | 58 + src/LOL.Assist.Core/IServices/IGameService.cs | 23 + src/LOL.Assist.Core/IServices/ILOLService.cs | 17 + src/LOL.Assist.Core/IServices/ILcuService.cs | 125 + .../IServices/IWindowService.cs | 20 + src/LOL.Assist.Core/LOL.Assist.Core.csproj | 16 + src/LOL.Assist.Core/LolAuthProvider.cs | 66 + src/LOL.Assist.Core/LolConnect.cs | 165 + .../Models/ChampSelectSessionRequest.cs | 16 + .../Models/ConversationsMsgRequest.cs | 23 + .../Models/ConversationsResponse.cs | 117 + .../Models/GameTeamResponse.cs | 54 + src/LOL.Assist.Core/Models/Hero.cs | 99 + .../Models/HeroListResponse.cs | 18 + .../Models/HeroPositionRecommend.cs | 28 + src/LOL.Assist.Core/Models/LcuMessageBase.cs | 6 + .../Models/PerkCurrentPageResponse.cs | 16 + src/LOL.Assist.Core/Models/PerkPageRequest.cs | 34 + src/LOL.Assist.Core/Models/Position.cs | 33 + src/LOL.Assist.Core/Models/RuneResponse.cs | 72 + src/LOL.Assist.Core/Models/SelectHeroGroup.cs | 18 + .../Models/SessionActionsRequest.cs | 9 + .../SubscribeMessage/ChampSelectMessage.cs | 119 + .../SubscribeMessage/ReadyCheckMessage.cs | 30 + .../SelectSummonersMessage.cs | 32 + .../Models/SummonerIconRequest.cs | 6 + src/LOL.Assist.Core/Services/DbService.cs | 82 + src/LOL.Assist.Core/Services/WindowService.cs | 99 + .../LOL.Assist.Swagger.csproj | 14 + src/LOL.Assist.Swagger/Program.cs | 45 + .../Properties/launchSettings.json | 31 + .../appsettings.Development.json | 8 + src/LOL.Assist.Swagger/appsettings.json | 9 + src/LOL.Assist.Swagger/wwwroot/help.json | 1 + src/LOL.Assist.Swagger/wwwroot/openapi.json | 75670 ++++++++++++++++ .../wwwroot/v1-api-docs.json | 1 + .../wwwroot/v2-swagger.json | 1 + .../wwwroot/v3-swagger-false.json | 1 + .../wwwroot/v3-swagger-true.json | 1 + .../wwwroot/v3-swagger.json | 1 + 助手.png | Bin 0 -> 126699 bytes 83 files changed, 80862 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 lol-assist.sln create mode 100644 src/LOL.Assist.App/App.xaml create mode 100644 src/LOL.Assist.App/App.xaml.cs create mode 100644 src/LOL.Assist.App/AssemblyInfo.cs create mode 100644 src/LOL.Assist.App/Global.cs create mode 100644 src/LOL.Assist.App/LOL.Assist.App.csproj create mode 100644 src/LOL.Assist.App/Model/HeroRuneGroup.cs create mode 100644 src/LOL.Assist.App/Model/RuneGroup.cs create mode 100644 src/LOL.Assist.App/Resources/Position_Challenger-Bot.png create mode 100644 src/LOL.Assist.App/Resources/Position_Challenger-Jungle.png create mode 100644 src/LOL.Assist.App/Resources/Position_Challenger-Mid.png create mode 100644 src/LOL.Assist.App/Resources/Position_Challenger-Support.png create mode 100644 src/LOL.Assist.App/Resources/Position_Challenger-Top.png create mode 100644 src/LOL.Assist.App/Resources/Resources.Designer.cs create mode 100644 src/LOL.Assist.App/Resources/Resources.resx create mode 100644 src/LOL.Assist.App/ViewModels/RunePopupViewModel.cs create mode 100644 src/LOL.Assist.App/ViewModels/RuneViewModel.cs create mode 100644 src/LOL.Assist.App/ViewModels/SelectHeroViewModel.cs create mode 100644 src/LOL.Assist.App/ViewModels/SettingViewModel.cs create mode 100644 src/LOL.Assist.App/Views/Controls/DelayTime.xaml create mode 100644 src/LOL.Assist.App/Views/Controls/DelayTime.xaml.cs create mode 100644 src/LOL.Assist.App/Views/Controls/HeroControl.xaml create mode 100644 src/LOL.Assist.App/Views/Controls/HeroControl.xaml.cs create mode 100644 src/LOL.Assist.App/Views/MainWindow.xaml create mode 100644 src/LOL.Assist.App/Views/MainWindow.xaml.cs create mode 100644 src/LOL.Assist.App/Views/Pages/RunePage.xaml create mode 100644 src/LOL.Assist.App/Views/Pages/RunePage.xaml.cs create mode 100644 src/LOL.Assist.App/Views/Pages/SettingPage.xaml create mode 100644 src/LOL.Assist.App/Views/Pages/SettingPage.xaml.cs create mode 100644 src/LOL.Assist.App/Views/RunePopupWindow.xaml create mode 100644 src/LOL.Assist.App/Views/RunePopupWindow.xaml.cs create mode 100644 src/LOL.Assist.App/Views/SelectHeroWindow.xaml create mode 100644 src/LOL.Assist.App/Views/SelectHeroWindow.xaml.cs create mode 100644 src/LOL.Assist.App/build.cmd create mode 100644 src/LOL.Assist.Core/DbModels/Config.cs create mode 100644 src/LOL.Assist.Core/DbModels/HeroRune.cs create mode 100644 src/LOL.Assist.Core/DbModels/SelectHero.cs create mode 100644 src/LOL.Assist.Core/Enums/ConfigKeyEnum.cs create mode 100644 src/LOL.Assist.Core/Enums/SelectSessionEnum.cs create mode 100644 src/LOL.Assist.Core/Enums/SubscribeEventUri.cs create mode 100644 src/LOL.Assist.Core/IServices/IDbService.cs create mode 100644 src/LOL.Assist.Core/IServices/IGameService.cs create mode 100644 src/LOL.Assist.Core/IServices/ILOLService.cs create mode 100644 src/LOL.Assist.Core/IServices/ILcuService.cs create mode 100644 src/LOL.Assist.Core/IServices/IWindowService.cs create mode 100644 src/LOL.Assist.Core/LOL.Assist.Core.csproj create mode 100644 src/LOL.Assist.Core/LolAuthProvider.cs create mode 100644 src/LOL.Assist.Core/LolConnect.cs create mode 100644 src/LOL.Assist.Core/Models/ChampSelectSessionRequest.cs create mode 100644 src/LOL.Assist.Core/Models/ConversationsMsgRequest.cs create mode 100644 src/LOL.Assist.Core/Models/ConversationsResponse.cs create mode 100644 src/LOL.Assist.Core/Models/GameTeamResponse.cs create mode 100644 src/LOL.Assist.Core/Models/Hero.cs create mode 100644 src/LOL.Assist.Core/Models/HeroListResponse.cs create mode 100644 src/LOL.Assist.Core/Models/HeroPositionRecommend.cs create mode 100644 src/LOL.Assist.Core/Models/LcuMessageBase.cs create mode 100644 src/LOL.Assist.Core/Models/PerkCurrentPageResponse.cs create mode 100644 src/LOL.Assist.Core/Models/PerkPageRequest.cs create mode 100644 src/LOL.Assist.Core/Models/Position.cs create mode 100644 src/LOL.Assist.Core/Models/RuneResponse.cs create mode 100644 src/LOL.Assist.Core/Models/SelectHeroGroup.cs create mode 100644 src/LOL.Assist.Core/Models/SessionActionsRequest.cs create mode 100644 src/LOL.Assist.Core/Models/SubscribeMessage/ChampSelectMessage.cs create mode 100644 src/LOL.Assist.Core/Models/SubscribeMessage/ReadyCheckMessage.cs create mode 100644 src/LOL.Assist.Core/Models/SubscribeMessage/SelectSummonersMessage.cs create mode 100644 src/LOL.Assist.Core/Models/SummonerIconRequest.cs create mode 100644 src/LOL.Assist.Core/Services/DbService.cs create mode 100644 src/LOL.Assist.Core/Services/WindowService.cs create mode 100644 src/LOL.Assist.Swagger/LOL.Assist.Swagger.csproj create mode 100644 src/LOL.Assist.Swagger/Program.cs create mode 100644 src/LOL.Assist.Swagger/Properties/launchSettings.json create mode 100644 src/LOL.Assist.Swagger/appsettings.Development.json create mode 100644 src/LOL.Assist.Swagger/appsettings.json create mode 100644 src/LOL.Assist.Swagger/wwwroot/help.json create mode 100644 src/LOL.Assist.Swagger/wwwroot/openapi.json create mode 100644 src/LOL.Assist.Swagger/wwwroot/v1-api-docs.json create mode 100644 src/LOL.Assist.Swagger/wwwroot/v2-swagger.json create mode 100644 src/LOL.Assist.Swagger/wwwroot/v3-swagger-false.json create mode 100644 src/LOL.Assist.Swagger/wwwroot/v3-swagger-true.json create mode 100644 src/LOL.Assist.Swagger/wwwroot/v3-swagger.json create mode 100644 助手.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ee5385 --- /dev/null +++ b/.gitignore @@ -0,0 +1,362 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd diff --git a/README.md b/README.md new file mode 100644 index 0000000..4f015fc --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +## 一、功能概述 + +懒得添加桌面图标,下载发布的exe直接双击运行,配置后会在同目录产生config.db配置数据文件 + +| 功能概述 | 功能概述 | +| -- | -------- | +| 🎉 自动接受对局 | 自动接受对局 | +| 🎉 自动禁用英雄 | 按照列表顺序优先禁用英雄,也可根据列表随机禁用英雄 | +| 🎉 自动选择英雄 | 排位赛根据游戏中真实位置选择英雄,匹配模式根据设置的位置选择英雄,根据列表顺序选择,也可根据位置列表随机选择 | +| 🎉 自动设置预设符文 | 根据选择英雄的配置预设符文,预设符文由符文页页面管理 | + +![助手.png](助手.png) + +## 二、目的 + +​ 编写这个工具的主要原因有: + +​ 1、已经接受对局了,老婆让我去晾衣服🫠🫠🫠 + +​ 2、和朋友玩儿匹配的时候抢英雄😁😁😁 + +​ 3、基本没有画过桌面客户端,随便回忆下学的内容🤔🤔🤔 + +## 三、资料查询 + +​ [Github LCU 主题](https://github.com/topics/lcu-api)、[官网文档](https://developer.riotgames.com/)、 [社区文档](https://riot-api-libraries.readthedocs.io/en/latest/index.html) + +​ https://discord.com/channels/ + +​ 博客:https://hextechdocs.dev/ + +​ swagger:https://www.mingweisamuel.com/lcu-schema/tool/#/ + +### 1、websocket + +​ https://hextechdocs.dev/getting-started-with-the-lcu-websocket/ + +### 2、项目参考 + +​ PoniLCU:https://github.com/Ponita0/PoniLCU + +​ https://github.com/real-web-world/hh-lol-prophet/blob/main/services/lcu/api.go + +​ https://github.com/Terevenen2/LOL-Client-TOOL/blob/avalonia/MainWindow.axaml.cs + +​ https://github.com/XHXIAIEIN/LeagueCustomLobby + +### 4、数据信息 + +​ 英雄列表:https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js + +​ 头像地址:https://game.gtimg.cn/images/lol/act/img/champion/Annie.png + +​ 英雄详情信息:https://game.gtimg.cn/images/lol/act/img/js/hero/1.js + +​ 装备信息:https://game.gtimg.cn/images/lol/act/img/js/items_ext/items_ext.js + +​ 符文信息:https://game.gtimg.cn/images/lol/act/img/js/runeList/rune_list.js + +​ 数据分析:https://www.op.gg/ + + +## 四、获取端点信息 + +获取启动信息 `wmic process where name='LeagueClientUx.exe' GET commandline ` + +找到参数--remoting-auth-token、--app-port + + + diff --git a/lol-assist.sln b/lol-assist.sln new file mode 100644 index 0000000..076c032 --- /dev/null +++ b/lol-assist.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{72564A64-8F77-4221-9E81-6F08A3B2F73E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LOL.Assist.App", "src\LOL.Assist.App\LOL.Assist.App.csproj", "{6E9E2817-D723-49D1-9F7E-AECB8454015F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LOL.Assist.Core", "src\LOL.Assist.Core\LOL.Assist.Core.csproj", "{315A3128-E7DD-4709-89CF-745FE8E2642F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LOL.Assist.Swagger", "src\LOL.Assist.Swagger\LOL.Assist.Swagger.csproj", "{7BE0491E-00EA-4517-9B28-F229BE9DCFAE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6E9E2817-D723-49D1-9F7E-AECB8454015F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E9E2817-D723-49D1-9F7E-AECB8454015F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E9E2817-D723-49D1-9F7E-AECB8454015F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E9E2817-D723-49D1-9F7E-AECB8454015F}.Release|Any CPU.Build.0 = Release|Any CPU + {315A3128-E7DD-4709-89CF-745FE8E2642F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {315A3128-E7DD-4709-89CF-745FE8E2642F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {315A3128-E7DD-4709-89CF-745FE8E2642F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {315A3128-E7DD-4709-89CF-745FE8E2642F}.Release|Any CPU.Build.0 = Release|Any CPU + {7BE0491E-00EA-4517-9B28-F229BE9DCFAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BE0491E-00EA-4517-9B28-F229BE9DCFAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BE0491E-00EA-4517-9B28-F229BE9DCFAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BE0491E-00EA-4517-9B28-F229BE9DCFAE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6E9E2817-D723-49D1-9F7E-AECB8454015F} = {72564A64-8F77-4221-9E81-6F08A3B2F73E} + {315A3128-E7DD-4709-89CF-745FE8E2642F} = {72564A64-8F77-4221-9E81-6F08A3B2F73E} + {7BE0491E-00EA-4517-9B28-F229BE9DCFAE} = {72564A64-8F77-4221-9E81-6F08A3B2F73E} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A4E8E314-8CEE-426F-A541-D14273BB85D4} + EndGlobalSection +EndGlobal diff --git a/src/LOL.Assist.App/App.xaml b/src/LOL.Assist.App/App.xaml new file mode 100644 index 0000000..eb9f5a7 --- /dev/null +++ b/src/LOL.Assist.App/App.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/src/LOL.Assist.App/App.xaml.cs b/src/LOL.Assist.App/App.xaml.cs new file mode 100644 index 0000000..2f1c044 --- /dev/null +++ b/src/LOL.Assist.App/App.xaml.cs @@ -0,0 +1,60 @@ +using CommunityToolkit.Mvvm.DependencyInjection; +using FreeSql; +using LOL.Assist.App.ViewModels; +using LOL.Assist.App.Views; +using LOL.Assist.Core; +using LOL.Assist.Core.DbModels; +using LOL.Assist.Core.Enums; +using LOL.Assist.Core.IServices; +using LOL.Assist.Core.Models; +using LOL.Assist.Core.Services; +using Microsoft.Extensions.DependencyInjection; +using Refit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Navigation; +using Wpf.Ui.Mvvm.Contracts; +using Wpf.Ui.Mvvm.Services; + +namespace LOL.Assist.App +{ + + /// + /// Interaction logic for App.xaml + /// + public partial class App + { + private static LolConnect _lolConnect=new LolConnect(); + protected override void OnStartup(StartupEventArgs e) + { + IServiceCollection services = new ServiceCollection() + .AddSingleton(); + + services.AddSingleton(RestService.For(_lolConnect.GetHttpClient())); + RefitSettings settings = new RefitSettings(new NewtonsoftJsonContentSerializer()); + services.AddSingleton(RestService.For("https://lol.qq.com", settings)); + services.AddSingleton(RestService.For("https://game.gtimg.cn", settings)); + services.AddSingleton(new FreeSqlBuilder() + .UseConnectionString(DataType.Sqlite, $"Data Source={AppContext.BaseDirectory}config.db") + .UseAutoSyncStructure(true).Build()); + services.AddScoped(); + services.AddScoped(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + Ioc.Default.ConfigureServices(services.BuildServiceProvider()); + base.OnStartup(e); + } + protected override void OnLoadCompleted(NavigationEventArgs e) + { + _lolConnect=_lolConnect.Connect(); + } + + } + +} diff --git a/src/LOL.Assist.App/AssemblyInfo.cs b/src/LOL.Assist.App/AssemblyInfo.cs new file mode 100644 index 0000000..2211234 --- /dev/null +++ b/src/LOL.Assist.App/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly:ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/src/LOL.Assist.App/Global.cs b/src/LOL.Assist.App/Global.cs new file mode 100644 index 0000000..14d5cf0 --- /dev/null +++ b/src/LOL.Assist.App/Global.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using LOL.Assist.Core.Enums; +using LOL.Assist.Core.Models; +using LOL.Assist.Core.Models.SubscribeMessage; +using Newtonsoft.Json.Linq; + +namespace LOL.Assist.App; + +/// +/// 全局配置信息 +/// +public static class Global +{ + /// + /// 角色列表 + /// + public static List Heroes { get; set; } = new List(); + + /// + /// 位置信息 + /// + public static List Positions = new List + { + new Position("上路","/Resources/Position_Challenger-Top.png","top"), + new Position("打野","/Resources/Position_Challenger-Jungle.png","jungle"), + new Position("中路","/Resources/Position_Challenger-Mid.png","middle"), + new Position("下路","/Resources/Position_Challenger-Bot.png","bottom"), + new Position("辅助","/Resources/Position_Challenger-Support.png","utility"), + }; + + /// + /// 符文列表 + /// + public static List Runes { get; set; } = new List(); + + /// + /// 当前游戏开始cell id + /// + public static int? LocalPlayerCellId { get; set; } + /// + /// 存储会话信息 + /// + /// + public static void GameSessionHandle(JToken gameFlow, string uri, string type) + { + LocalPlayerCellId = gameFlow.ToObject()?.LocalPlayerCellId; + } + +} \ No newline at end of file diff --git a/src/LOL.Assist.App/LOL.Assist.App.csproj b/src/LOL.Assist.App/LOL.Assist.App.csproj new file mode 100644 index 0000000..998b619 --- /dev/null +++ b/src/LOL.Assist.App/LOL.Assist.App.csproj @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + WinExe + net7.0-windows + enable + true + + + diff --git a/src/LOL.Assist.App/Model/HeroRuneGroup.cs b/src/LOL.Assist.App/Model/HeroRuneGroup.cs new file mode 100644 index 0000000..32ec225 --- /dev/null +++ b/src/LOL.Assist.App/Model/HeroRuneGroup.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using CommunityToolkit.Mvvm.ComponentModel; +using LOL.Assist.Core.DbModels; +using LOL.Assist.Core.Models; + +namespace LOL.Assist.App.Model; + +public partial class HeroRuneGroup:ObservableObject +{ + public HeroRune HeroRuneBase{get;set;} + /// + /// 主要系别符文信息 + /// + public List Primary { get; set; } + + /// + /// 副系及成长符文信息 + /// + public List SecondGrowing { get; set; } +} \ No newline at end of file diff --git a/src/LOL.Assist.App/Model/RuneGroup.cs b/src/LOL.Assist.App/Model/RuneGroup.cs new file mode 100644 index 0000000..11d0cfe --- /dev/null +++ b/src/LOL.Assist.App/Model/RuneGroup.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Windows; +using CommunityToolkit.Mvvm.ComponentModel; +using LOL.Assist.Core.Models; + +namespace LOL.Assist.App.Model; +/// +/// 符文分组信息 +/// +public partial class RuneGroup:ObservableObject +{ + /// + /// 主系选中状态 + /// + [ObservableProperty] + private double _primaryOpacity = 0.4; + /// + /// 副系显隐藏 + /// Visible + /// Hidden + /// Collapsed + /// + [ObservableProperty] + private Visibility _secondVisibility; + /// + /// 副系选中状态 + /// + [ObservableProperty] + private double _secondOpacity = 0.4; + /// + /// 系别 + /// + [ObservableProperty] private RuneResponse _root; + /// + /// 基石信息 + /// + public List Base { get; set; } + + /// + /// 一级符文信息 + /// + public List Valiant { get; set; } + /// + /// 二级符文信息 + /// + public List Legend { get; set; } + /// + /// 三级符文信息 + /// + public List Combat { get; set; } +} diff --git a/src/LOL.Assist.App/Resources/Position_Challenger-Bot.png b/src/LOL.Assist.App/Resources/Position_Challenger-Bot.png new file mode 100644 index 0000000000000000000000000000000000000000..48d922a00e2a06fab5bf231cfa74616e721d9e62 GIT binary patch literal 6743 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 E05=h9;s5{u literal 0 HcmV?d00001 diff --git a/src/LOL.Assist.App/Resources/Position_Challenger-Mid.png b/src/LOL.Assist.App/Resources/Position_Challenger-Mid.png new file mode 100644 index 0000000000000000000000000000000000000000..316617450edcbb93635a8c2559d2d286aedcd139 GIT binary patch literal 7731 zcmaKRcQjnz+P~gA(TV6pnHhu8qqk8)2nk`v3?|A9GkWg~A&4?a2ttV7B1P}L6G@0p zqD3cCesb^q-rxJjyWX?bIeYKtJpK7RYp-*5g1M1!;kVAp*Pxkg7yPq|vB5HaHs-sIn8< zLk9MjN5MXR|-6kIGBLHhr1_M*fUPeLM2`C2jx6@TUoQ3`ozRKPIZRjuKl{d;}-l(ghz}$7v zPCgz;Pn@BSn&8zN83YQU3<4uy3Lpql8U{unr2$G{fHWK-50FM6kVpk32oelb1plMw zf0LKj*40te1#0U-06IXRE<{OJQ&C4jTN?z@RnXG|$^Rp3=!wO_Je`pL*hXF1{*SEI z|0%1i?Tv)t(B5~@X!n0mVD5^>p|P%LjDWWG->NGLh~GtdBG7(ViN9s~chovaZU)X@1q~Qu6u(TXl2_Yx10E9aM5rY4bNBocc z{TruOl&d%}|G1;91crd+kwBQVGX$U{eWe>Btt1bDOC!JtMIhYS35--!5R|=gQT8u% z{s)x)Azk6~@ASWoakcnwYaul*54-tqsqV@HkQ*$fDI*Q^;S zAYoMOZz$+vgWsE~^RZP&4Cx0K*M2>RP9l^Evjbog6~kQAg0naHsq&QYRKr)ulrWU_ zlaG|rDsQq6L0M`bt>Usk$MA`Nq_C%B#KP{`uRnVv1$j1>@RBL(@f{``qQr%>w*8Pz zBcKVZB7fWE^TqHbid%|AZ;8k0!##;`qy>LoF`iL|EVa@z1_y3*>c0LFsmb|P=2W7b zM)!8NLquJ9{~S%5^^$j4!atucG^9=9J1m2pFXqhGuvWG>WOe5W=}{42&Lf{y1_ zeLMC~I<8Z-o7)ZcyH5X^okgo@Oa`sJ6l2m`T#waYjtLSbiF&q8(SwVV`2s!vH(g9!MBqNq2?HCKl|0Htj&R6-U8xbp;EavuOUHeBucJ_}Zj5#L! z4nV%1e*zA-614MYmbFaVNP1VDjykD+sE%(1fS&toeceg4oNEwJZKSxTOvw;U|3e^3 zBz$mPld>;HPH1cYQPZTMDP4h`OqfI}bW)NcwKQD@mP*c~u|sQFN$c}&Ax-zVb#65# zMZr0~Z#8yqH)3v^`BLrugo}NHg9tlQpn=O&ww)q5f7^8x-`)0@)xO$y+jFI+r+K>t z`EN8 z#`!R#*Qx857u30&4h?h7}SGY~PK~LA2dt zSN>&1Pg>%GvE)o+671kKl+=AMGb=%1lATJP_N{4n2pP4ir%GtgYa-Y*xl%8lpHyRN z+&C81KKrb+$n~ik#X%mBj7|&0N@FIq6GmPBeDifbKVmrM)1ch#<|0l`HR_nA&U>Hy zzC?(}MAHz}{{qyxvzB1SByh<%Q#3&$(Lb*#&~b$H z3S;Qt8bi&7ec)@P5+p9mc>&EH3xPj<`+RvnFT`}|pYm#Wf7>d0v2=$SLQK+k3n#UZ z%5CbaemUm{+s#+Ux3X?NR#~7o^T{9!51%l^M*EZ<2A}JEIL0Zoc@rUMrQH~#ZX`c! z5e+Pe)R{(7SHlyk9OK7@UL#HUYioa>_usq-u2A7WG`EO4zkH52Y8Y|tYI>^TRq%?I zlCdRZr^Rv~2oc+no7Y*Y5WrB#vE+dxjt({zmuJV+@e!5_{rO6=(0Cs+tNsRD*FAg7 zEvDQYqf0sx6CxW1#W9Xi-{C)G<~s`HxopG?s~IB*sZ<%FZsm1fLZl|{Uc-dng^i3d zNdT)ZGK=n@HLjKCJ7rC}4R)#&9(rP_s+~Y_n-^hcfp|9g!Gyf>|ik=>XP}9{=m(P z=nI=VY2ACNdk&2!`WX+BPxO#p?BPa?8zNc!<#fwS%WC>5d8!s9qYH8bB~7{#9K~j> zRMb&MQ0))7u<%y71wf#T77PQu{K?5_4~jQ=*4~diBH_%kagQI%UUz(4md(Q3rQ_xG zh%tW-40^=0sB}7-$ad3b3O@~LD`#uJRwEJflzi+iiFm5{iSBA`m@LI6KSgO-Wcz@S za@x24aSbWTt>yflmGPa3U&B%Njk7L{xoTjIzGg?rHzywLqpH zj^V>+VK*A@c07qKql)YL!k0wHSEAMmDpvEN%(Jz!nKxKM;E0oZmx6bRD}GFOZMkgN z?Zs#vaM2a5y@$FH`%7?gGE+``IW{2KJ*#3GTP3|6O|timdJ~RU8l83D^gJ9~OC2co zn#(bXN_P{hPd74kOw0KsZ83sALMXBBOfWEQq8 z-6Qp#HuE|;T~(@SJN?O`%K0}i*1wiXx5R)7KYq|GWtY?w6w+PWZbaL>Jz8t$yyxkV zw9zB?{V@M0)4Q;lM^O?-CzehhX;~=@h+ypE!tS3JQG+`2sYX;LIpPL0p&Wbpe7&G# zY=1>BXP&s+=8cLUYb{%1cRi2OY;Wg~5VDm!-B~zKJLlWi46`k}fZ!^J=uD)C{|Q#3 z^K@>^v8~FJtA8tHN>K<&^s?ZT0iqDX#zj$+Wn^B^xBtuU77Z)F?=er9FN%+SS`I=H zq3wLlm<7wc3_vYkv|{fS6O3q-7XMU!Mr+%^u*Ib3%=ib1YciLn`7UQW5s85aqvWtkJWr z5y*H6Mh;<2!&z6Wz1Bki^gg=kl$CJAN1G3ZFUgbOePFxI=Py4HqkcI<%PMaYJ8Qd% zJhL&6x}S5iyY;sYzb(E(&GXuU!C|ePst8%Ydf$F~JBq|5K3lsi;ar*>X6m)WRw#ZQ zG5h`U9ynqAr!QD4C;3b8g^2sFjvLgbi@5f(!Vey+_?Z>7ZC!vm^8-FYqU3CVA^X7K z^V@J=J9#LJ!E;9uPltD0L8s`hwV&6d&}EwP5o|@_9s-2YJ37qWYXy%+BzesI)Q=kD zYIX>p#6y}%oDgg@$UilL@BwzqR%@DSUCE9@UgJXe9uE53{O01%!?Ev2VQS%O^A?zL zZL-lp`IVre+6nKOViQy~-lALFMk>-$T51vU)Bs@tP}Te#VyQMOAJ`)g1aJd;6~Z`x zaU+r@&L?X}XHN60ui;Aw*`$e=WTiHb>1la`>gD4sso|zeC0}2bLR>x_$*#_XEygWy z5sz9bK$gv~?b);>v&VkO!O!@=e;zd0CD0FDn023$!An?=^u1X6_>nkbiB{X>fv)G0 zaIamcjAwxjhdn!XvKG2IHTETOolntei7bNE?D5UB&RP_4+PVOpaTrvYyOhOlJE4^6 zJt~LD5wWL8@X<-5rbEE6MQ?r1AMn$@cNvx#*>Hn?c$TX^-{-Q1$ri`fMRMcu`` z{dammz((^G@%jGa&ky|jMsGiR@|-cVid;@?aM%!`lK(q*#O5G%y;v!Pg}0T)*iu-a zWcpd~VnP@vuYGzXZ}tNI$3^7_&843^_wCss{*%OFyuBqpJUszD=?%sQE#FS>jFv?4 zK7~Y8AgpdbVR>4M<%^HJY>Wf8WMD)n3zARTkM9h25-c2(`zzDtM_qnzJgD$TaEUx4 z1x(u7?r=16&vIqi-JnRIwd-cT?O*Ht%1(;-&#*O^3F{lYu5n;VA+{baBws2Ch4t|j z)-jnRjX$@mezVX)8LX*sXeam-BU5726QJv5RKbL#%WCG#+8x0w8ZtKvmXZez3lhZ$ zq?9Ow4%{~_!vYkoRhzR{cuB+vsl&BJ77K?qbWjDC3|X4_H|!?uibV=J_6*w_jdtMJ?ki(l}b$h7+@1XbTry3(Xz?6N-i;eI>}J25p^1 zK;9(1EQnL<->1${dsV)7t*zvL4j5HxM1tiwh-f>D+D!(AKEb~Vw7)&u|L(sXJH z((*2auxl2-7W(P(SjM;vXH13@ocWzLR1YrbZ5mNBRlbag9|5@%Dk8eCC%IHS0JP-F zUFBc52G}B|1O*Yqql&K`Xibsidp2+G;U2Pn70#WR&5O9qtZX4Sk)HZKI=cI^qAVg8 zDpkEM%JBGUxuo^QogwE0fg5C9R`K-oLRnCj-Ki3Bc}$QvLF9BNs=R*5n&y?EUOgX* zWYa1Ceqx5-sGh@Eyn$#;SZ~8-g zZHH#}<)zp0aB7!Yh?+}4qYvIh@@qWf>kCKgX?&t_cRe2=diG*stfIG$em7FdZr!Qo z%{8HRMfcfeDOIVvo~V3wGa*1FKmAe8_{qrJK|0#KzQc=*aGln9ByR40jKLE@#FSi+ zyKrm3Ku%+}LJ|GD*KN9^Ft(X=(bRx-WND+FXfH<>e{@ILGm8}Qb^X+5iI5rW&*L)V z1>Pj3J?~`%BZ>O;wByUNX2htzdJD@C+Kpp)Im5}!d9Yabw-quXQH|{``EcR;6t1u6 z@~$VgmNnbCZ35^<)=#S>d182Dc6qCrm$YWRw-7cJFWu95vcY8xEgV4r5ICNO#j`YP zbJ}@`*$``%EBNV~geBnPTwMS9gS=MU;q?3>t%ym>Cvj$b$b1TL#L(NdCK1C&FJ5h$=Iy`h zUgEt;;WF@qNYIwAELyKhb?#!ReyBD$gy)B>e$PYi&<)4YO0Fq!e~Fk|aP&*=LXmVc z)Jyj&ZBn4irr%oLwiyS;lb4)d(~7yP9f+l+gzsyuIq7< zw6<_%y9scRDFS<<#W;HMOwB7`%gC@gSlgJK-Aoh%Qf4u%6fzzTSSk~-dH?nrY0K>n z-X2L;F5lXr8Y6LQdGldf+lWlPrDz^EV50|1Q@9`X+pRR#v*BdfS4b z$%P`CoeMPn1j#f1D0NtxG%EOk!{gN$>|L|#yNOg7(~tX==&E)>_$U=nY+%?h)mBY{ zz{+KGkG`wW(M+*tJkov-ENz*d|NQty<@2f+*5OC9i9z27&rV@3cm6zG`tI~&`m0vZ z8s;ucV><~hxuP~!h1q;>Kz#c}XsxmR9Gfuarxtc{z)nA>{moesZH=py97T0^aozXh%va;= zpvnxEMTu&avP3G91f>~Et(Ry9r=ZPu=RIc0AFe*bFWV2w`R}ksS=coOUq^S}!i2xL zPc)x@o9@N9yH3E00A*fdcV3K7D9pMH_kikfA!WF0^8P(0E@*rn{z!(oYYj=TX3#L0 zm_8{~O>AFDNHjNL@}bZ8a4^aI^YDd}|NY3L?)~lil{Q{CKjwVGeCvnd7wOM~f4dz= zn^`o!3hv^)h{U!1+*+>htlE9f=D!#XyCBLDFSAeP}`fi~JyjnAKrd0OTe0{mqPlYjuz7cA_L$OAQ>@r;|F+&rdLH5FOETv*OvnXTLT+vlrhwo(L*>_bt?+D#6zgV|ZjE$)#l+;#l*M5-quiCIOpwK1U@ zi5(rG&Gw$d?@?9fEu=xd)Ya=R*!o&s13j9pUT4f*v!K-m4sQ1-G+GPjFz<<@bQMZz zH!50M_=e_8OFxJkk>tkpZL&9cyhV5|6x-8o!~DO%T@23kf_lRmQR#$q+ahY+}of}N3*JeCOynbJsP*+zkg~o6hI8FVFCJSUU$BbeRQDMI*s%P2Xq`G+3ZH z(L4*REMsx=M6){2eB#p-AyC(MrfDnPMw`rj%Jm=-Og#H8UK4rd>(IUYD`bm%Vn>3O z*mQiqC#@;)pv6@+nTEtrV)D^8;TG&M3-x3%p}zZ!fiJjp?8U=b&h(kLk_25yaM^sGG1tGwKEOtefliskfk({W~9dSNGj6+pbs3_hFp##uBY$LHGzU~17p z%MFowQ|qbcQV){c?p0i`kS`GwvKVa!dcGX=B%i+^-N&Xc`VV}Td6uyBd7k;bS{@RU zCooPC7uRZekDWMdmA2MkM~NZw&3m_;*r`R|J=)q0=035`Qyk^H%QYK1s}3XZj3QOX z#zy=3o04thgb&;9wS!f?H9R1^EVkkQ{$wnsTylw#!j%~`I-yIQ>9%71tDoQ3(uky`u){)(m101P zWnwu#X^%@_%QVTSC1sn);Pi#JEx|Z}XDUhSCY5hxU%B*=E44I#EJgYjp8-r3C)gejhKq{h0cK*JAdiMtYlx?{O}ge{dOh+$-1tR z^jYv!VwU&zBa1;cO0V2JAN`>%i-Nw9(|NJp$eofi!BjdK#?sn+unU40n@KeSj1~wA zIguULTe?HDAv|D}_=#M656G7(X^mR@7~uh%49BKFI^udoT<{I=_zq=tZN3{fLvc?c zJwd{npf&YW&<2M1$ZkM|32u1w2dFiWW!VXk_R)GgHO%|x4&3w?c1HdN zzAVx}lx0P5r?Yhd+|a{WzOr>YVKJv9Bam&Q+2m8>{i491pVbw0dPs|2c zyi)LCa9H^YBZO7Nm&ahyt%PmQ8`o}$cg~`bGwu=ixHto*C8)HG-tK%Ae>RBegY|Eg zPxQYx#ibMgw2+w);vQ~RE`zmfC5@Dgq|&Dsc?BHxx#hO~=SPk5^1ELYnL^{I>B?|4 z6Ry)J;;ifpwYW!};V-}DX+Foo*i(q_zxJ4i#Uj#RjoHvdL%W8d1WxHS#%U;L!88Bg z28)2rhXF#*#bau}uFT>kB!lr{IdWqxko<;@WgR~nTh@-mJ^4;Bc%yJjw8GDx(o?h>8A8GL^&~;3O(Z|sv1lo&NVQ)*-Ph}|ZX5627ed&Bz`#&$JiI4yM@>*>xY5wmi4G+<; f{g9toM5IJDpic|(t;Lgnk8urkO?9fY93%f9-6%L5 literal 0 HcmV?d00001 diff --git a/src/LOL.Assist.App/Resources/Position_Challenger-Support.png b/src/LOL.Assist.App/Resources/Position_Challenger-Support.png new file mode 100644 index 0000000000000000000000000000000000000000..a61e184b0791c41af727d6258f5eb32b3d6519f4 GIT binary patch literal 8091 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 d`-W5)CkCzJg_QF?y}d2R(NNJ$_9vs5R?MJ|v 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 Rb^rOlgV5C1c&%n1`acAAFZ}=j literal 0 HcmV?d00001 diff --git a/src/LOL.Assist.App/Resources/Resources.Designer.cs b/src/LOL.Assist.App/Resources/Resources.Designer.cs new file mode 100644 index 0000000..8f6662a --- /dev/null +++ b/src/LOL.Assist.App/Resources/Resources.Designer.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace LOL.Assist.App.Resources { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LOL.Assist.App.Resources.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Position_Challenger_Bot { + get { + object obj = ResourceManager.GetObject("Position_Challenger-Bot", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Position_Challenger_Jungle { + get { + object obj = ResourceManager.GetObject("Position_Challenger-Jungle", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Position_Challenger_Mid { + get { + object obj = ResourceManager.GetObject("Position_Challenger-Mid", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Position_Challenger_Support { + get { + object obj = ResourceManager.GetObject("Position_Challenger-Support", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Position_Challenger_Top { + get { + object obj = ResourceManager.GetObject("Position_Challenger-Top", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/src/LOL.Assist.App/Resources/Resources.resx b/src/LOL.Assist.App/Resources/Resources.resx new file mode 100644 index 0000000..dcf4bdc --- /dev/null +++ b/src/LOL.Assist.App/Resources/Resources.resx @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\Position_Challenger-Bot.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Position_Challenger-Jungle.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Position_Challenger-Mid.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Position_Challenger-Support.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Position_Challenger-Top.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/src/LOL.Assist.App/ViewModels/RunePopupViewModel.cs b/src/LOL.Assist.App/ViewModels/RunePopupViewModel.cs new file mode 100644 index 0000000..cd5e3a5 --- /dev/null +++ b/src/LOL.Assist.App/ViewModels/RunePopupViewModel.cs @@ -0,0 +1,204 @@ +using System; +using CommunityToolkit.Mvvm.ComponentModel; +using LOL.Assist.Core.DbModels; +using LOL.Assist.Core.Models; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Newtonsoft.Json; +using RuneGroup = LOL.Assist.App.Model.RuneGroup; +using System.Windows.Controls; +using CommunityToolkit.Mvvm.DependencyInjection; +using LOL.Assist.Core.IServices; + +namespace LOL.Assist.App.ViewModels +{ + public partial class RunePopupViewModel : ObservableObject + { + private static readonly IEnumerable ValiantStyleNames = new List { "英武", "预谋", "宝物", "巧具", "蛮力" }; + private static readonly IEnumerable LegendStyleNames = new List { "传说", "追踪", "卓越", "未来", "抵抗" }; + private static readonly IEnumerable CombatStyleNames = new List { "战斗", "狩猎", "威能", "超越", "生机" }; + /// + /// 符文 + /// + [ObservableProperty] + private ObservableCollection _showRunes; + /// + /// 成长符文 + /// + [ObservableProperty] + private RuneGroup _showGrowingRunes; + + [ObservableProperty] + private HeroRune _selectHeroRune; + + private readonly IDbService _dbService; + /// + /// + /// + public RunePopupViewModel() + { + _dbService = Ioc.Default.GetService()!; + RefreshReloadRune(); + } + + public void RefreshReloadRune() + { + IEnumerable runeGroup = Global.Runes + .Where(p => !string.IsNullOrWhiteSpace(p.Key) && string.IsNullOrWhiteSpace(p.SlotLabel) && + string.IsNullOrWhiteSpace(p.StyleName)).Select(runeResponse => + { + List> groupBy = Global.Runes + .Where(p => p.StyleName == runeResponse.Name) + .GroupBy(p => p.SlotLabel) + .ToList(); + + return new RuneGroup + { + Root = runeResponse, + Base = groupBy.FirstOrDefault(p => p.Key == "基石")!.ToList(), + Valiant = groupBy.FirstOrDefault(p => ValiantStyleNames.Contains(p.Key))!.ToList(), + Legend = groupBy.FirstOrDefault(p => LegendStyleNames.Contains(p.Key))!.ToList(), + Combat = groupBy.FirstOrDefault(p => CombatStyleNames.Contains(p.Key))!.ToList(), + }; + }); + ShowRunes = new ObservableCollection(runeGroup); + ShowGrowingRunes = new RuneGroup + { + Valiant = GetGrowingRues(new int[] { 5008, 5005, 5007 }), + Legend = GetGrowingRues(new int[] { 5008, 5002, 5003 }), + Combat = GetGrowingRues(new int[] { 5001, 5002, 5003 }), + }; + SelectHeroRune = null; + } + + private List GetGrowingRues(int[] ids) + { + return ids.Select(p => + { + RuneResponse source = Global.Runes.FirstOrDefault(px => px.Id == p)!; + return new RuneResponse + { + GroupName = source.GroupName, + Icon = source.Icon, + Id = source.Id, + IsChecked = source.IsChecked, + Key = source.Key, + LongDesc = source.LongDesc, + Name = source.Name, + Opacity = source.Opacity, + ShortDesc = source.ShortDesc, + SlotLabel = source.SlotLabel, + StyleName = source.StyleName, + Tooltip = source.Tooltip, + }; + }).ToList(); + } + + /// + /// 获取英雄选中服务信息 + /// + /// + public void SaveSelectHeroRune() + { + if (SelectHeroRune == null|| SelectHeroRune.ChampionId <=0) + return; + RuneGroup defaultRuneGroup = new RuneGroup() { Root = new RuneResponse() }; + RuneGroup primaryOpacity = ShowRunes.FirstOrDefault(p => Math.Abs(p.PrimaryOpacity - 1) == 0) ?? defaultRuneGroup; + RuneGroup secondRunes = ShowRunes.FirstOrDefault(p => Math.Abs(p.SecondOpacity - 1) == 0) ?? defaultRuneGroup; + Dictionary selectRune = new Dictionary() + { + { + primaryOpacity.Root.Id, new int[4] + { + GetRuneCheckId(primaryOpacity.Base), + GetRuneCheckId(primaryOpacity.Valiant), + GetRuneCheckId(primaryOpacity.Legend), + GetRuneCheckId(primaryOpacity.Combat), + } + }, + { + secondRunes.Root.Id==0?1:secondRunes.Root.Id, new int[3] + { + GetRuneCheckId(secondRunes.Valiant), + GetRuneCheckId(secondRunes.Legend), + GetRuneCheckId(secondRunes.Combat), + } + }, + { + 2, new int[3] + { + GetRuneCheckId(ShowGrowingRunes.Valiant), + GetRuneCheckId(ShowGrowingRunes.Legend), + GetRuneCheckId(ShowGrowingRunes.Combat), + } + } + }; + string runeJson = JsonConvert.SerializeObject(selectRune); + SelectHeroRune!.RuneJson = runeJson; + _dbService.InsertOrUpdate(SelectHeroRune); + } + /// + /// 设置英雄选中服务信息 + /// + /// + public void SetSelectHeroRune(HeroRune? heroRune, TabControl primaryTab, TabControl secondTab) + { + SelectHeroRune = heroRune; + if (heroRune == null || string.IsNullOrWhiteSpace(heroRune.RuneJson)) + return; + Dictionary? selectRune = JsonConvert.DeserializeObject>(heroRune.RuneJson); + if (selectRune is not { Count: 3 }) + return; + foreach (var kvp in selectRune) + { + //成长符文 + if (kvp is { Key: 2, Value.Length: 3 }) + { + SetRuneCheckId(ShowGrowingRunes.Valiant, kvp.Value[0]); + SetRuneCheckId(ShowGrowingRunes.Legend, kvp.Value[1]); + SetRuneCheckId(ShowGrowingRunes.Combat, kvp.Value[2]); + continue; + } + + RuneGroup? rootRune = ShowRunes.FirstOrDefault(p => p.Root.Id == kvp.Key); + if (rootRune == null) + continue; + switch (kvp.Value.Length) + { + //主系 + case 4: + primaryTab.SelectedItem = rootRune; + SetRuneCheckId(rootRune.Base, kvp.Value[0]); + SetRuneCheckId(rootRune.Valiant, kvp.Value[1]); + SetRuneCheckId(rootRune.Legend, kvp.Value[2]); + SetRuneCheckId(rootRune.Combat, kvp.Value[3]); + break; + //副系 + case 3: + secondTab.SelectedItem = rootRune; + SetRuneCheckId(rootRune.Valiant, kvp.Value[0]); + SetRuneCheckId(rootRune.Legend, kvp.Value[1]); + SetRuneCheckId(rootRune.Combat, kvp.Value[2]); + break; + } + } + } + + private int GetRuneCheckId(IEnumerable? runes) + { + if (runes == null) + return 0; + return runes.FirstOrDefault(p => p.IsChecked)?.Id ?? 0; + } + private void SetRuneCheckId(IEnumerable? runes, int id) + { + if (runes == null || id == 0) + return; + RuneResponse? setRune = runes.FirstOrDefault(p => p.Id == id); + if (setRune == null) + return; + setRune.IsChecked = true; + } + } +} diff --git a/src/LOL.Assist.App/ViewModels/RuneViewModel.cs b/src/LOL.Assist.App/ViewModels/RuneViewModel.cs new file mode 100644 index 0000000..d98751d --- /dev/null +++ b/src/LOL.Assist.App/ViewModels/RuneViewModel.cs @@ -0,0 +1,91 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.DependencyInjection; +using LOL.Assist.App.Model; +using LOL.Assist.Core.DbModels; +using LOL.Assist.Core.IServices; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Newtonsoft.Json; +using LOL.Assist.Core.Models; + +namespace LOL.Assist.App.ViewModels +{ + public partial class RuneViewModel : ObservableObject + { + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private ObservableCollection? _heroRunes; + private readonly IDbService _dbService; + + public RuneViewModel() + { + _dbService = Ioc.Default.GetService()!; + RefreshHeroRune(); + } + partial void OnSearchTextChanged(string value) + { + RefreshHeroRune(); + } + + public void RemoveHeroRune(int championId) + { + _dbService.Delete(p => p.ChampionId == championId); + HeroRuneGroup? removeHero = HeroRunes?.FirstOrDefault(p => p.HeroRuneBase.ChampionId == championId); + if (removeHero == null) + return; + HeroRunes!.Remove(removeHero); + } + public void RefreshHeroRune() + { + IList data = _dbService.GetAll(string.IsNullOrWhiteSpace(SearchText) ? p => true : p => p.KeyWords.Contains(SearchText) || p.Name.Contains(SearchText)); + HeroRunes = new ObservableCollection(data.Select(p => + { + HeroRuneGroup heroRuneGroup = new HeroRuneGroup + { + HeroRuneBase = p, + Primary = new List(), + SecondGrowing = new List(), + }; + if (string.IsNullOrWhiteSpace(p.RuneJson)) + return heroRuneGroup; + Dictionary? selectRune = JsonConvert.DeserializeObject>(p.RuneJson); + if (selectRune is not { Count: 3 }) + return heroRuneGroup; + + foreach (var kvp in selectRune) + { + //成长符文 + if (kvp is { Key: 2, Value.Length: 3 }) + { + heroRuneGroup.SecondGrowing.AddRange(kvp.Value + .Where(runeId => runeId != 0) + .Select(px => Global.Runes.FirstOrDefault(pj => px == pj.Id) ?? new RuneResponse())); + continue; + } + + RuneResponse? rootRune = Global.Runes.FirstOrDefault(px => px.Id == kvp.Key); + if (rootRune == null) + continue; + switch (kvp.Value.Length) + { + //主系 + case 4: + heroRuneGroup.Primary.Add(rootRune); + heroRuneGroup.Primary.AddRange(kvp.Value + .Where(runeId => runeId != 0) + .Select(px => Global.Runes.FirstOrDefault(pj => px == pj.Id) ?? new RuneResponse())); + break; + //副系 + case 3: + heroRuneGroup.SecondGrowing.Add(rootRune); + heroRuneGroup.SecondGrowing.AddRange(kvp.Value + .Where(runeId => runeId != 0) + .Select(px => Global.Runes.FirstOrDefault(pj => px == pj.Id) ?? new RuneResponse())); + break; + } + } + return heroRuneGroup; + })); + } + } +} diff --git a/src/LOL.Assist.App/ViewModels/SelectHeroViewModel.cs b/src/LOL.Assist.App/ViewModels/SelectHeroViewModel.cs new file mode 100644 index 0000000..fffd83f --- /dev/null +++ b/src/LOL.Assist.App/ViewModels/SelectHeroViewModel.cs @@ -0,0 +1,56 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using LOL.Assist.Core.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; + +namespace LOL.Assist.App.ViewModels; + +public partial class SelectHeroViewModel : ObservableObject +{ + + [ObservableProperty] private string _searchText = string.Empty; + + [ObservableProperty] private int _showHeroColumns = 6; + + [ObservableProperty] private List _showHeroes = new(); + + [ObservableProperty] private int _showHeroRows; + + [ObservableProperty] private string? _selectPosition = string.Empty; + + + [ObservableProperty] private Visibility _showLoading = Visibility.Visible; + + + /// + /// 位置信息 + /// + [ObservableProperty] + private List _positions = Global.Positions; + + + partial void OnSearchTextChanged(string value) => LoadShowHeroes(); + partial void OnSelectPositionChanged(string value) => LoadShowHeroes(); + public void LoadShowHeroes() + { + ShowLoading = Visibility.Visible; + IEnumerable positionRecommend = SelectPosition switch + { + "top" => Global.Heroes.Where(p => p.PositionRecommend.Top >= 100).OrderByDescending(px => px.PositionRecommend.Top), + "jungle" => Global.Heroes.Where(p => p.PositionRecommend.Jungle >= 100).OrderByDescending(px => px.PositionRecommend.Jungle), + "middle" => Global.Heroes.Where(p => p.PositionRecommend.Mid >= 100).OrderByDescending(px => px.PositionRecommend.Mid), + "bottom" => Global.Heroes.Where(p => p.PositionRecommend.Bottom >= 100).OrderByDescending(px => px.PositionRecommend.Bottom), + "utility" => Global.Heroes.Where(p => p.PositionRecommend.Support >= 100).OrderByDescending(px => px.PositionRecommend.Support), + _ => Global.Heroes, + }; + ShowHeroes = (string.IsNullOrWhiteSpace(SearchText) ? + positionRecommend : + positionRecommend.Where(p => p.Name.Contains(SearchText) || p.KeyWords.Contains(SearchText))) + .ToList(); + var rows = (int)Math.Ceiling(1d * ShowHeroes.Count / ShowHeroColumns); + ShowHeroRows = rows <= 5 ? 5 : rows; + ShowLoading = Visibility.Collapsed; + } +} \ No newline at end of file diff --git a/src/LOL.Assist.App/ViewModels/SettingViewModel.cs b/src/LOL.Assist.App/ViewModels/SettingViewModel.cs new file mode 100644 index 0000000..865b458 --- /dev/null +++ b/src/LOL.Assist.App/ViewModels/SettingViewModel.cs @@ -0,0 +1,436 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.DependencyInjection; +using LOL.Assist.Core; +using LOL.Assist.Core.DbModels; +using LOL.Assist.Core.Enums; +using LOL.Assist.Core.IServices; +using LOL.Assist.Core.Models; +using LOL.Assist.Core.Models.SubscribeMessage; +using Newtonsoft.Json.Linq; +using Refit; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using Newtonsoft.Json; +using System.Diagnostics; + +namespace LOL.Assist.App.ViewModels; + +public partial class SettingViewModel : ObservableObject +{ + /// + /// 自动接受 + /// + [ObservableProperty] + private bool _autoAccept; + /// + /// 自动接受联动组件显隐 + /// + [ObservableProperty] + private Visibility _autoAcceptVisibility = Visibility.Collapsed; + /// + /// 自动接受延迟时间 + /// + [ObservableProperty] + private int _autoAcceptDelayTime; + + /// + /// 自动禁用 + /// + [ObservableProperty] + private bool _autoAcceptBan; + /// + /// 自动禁用联动组件显隐 + /// + [ObservableProperty] + private Visibility _autoAcceptBanHeroVisibility = Visibility.Collapsed; + /// + /// 自动禁用延迟时间 + /// + [ObservableProperty] + private int _autoAcceptBanDelayTime; + /// + /// 自动根据列表随机禁用 + /// + [ObservableProperty] + private bool _autoAcceptBanRandom; + /// + /// 自动禁用英雄列表 + /// + [ObservableProperty] + private ObservableCollection _autoAcceptBanHeroes = new(Enumerable.Range(0, 5).Select(i => new SelectHero + { + ChampionId = -1, + HeadPortrait = _positions[i].Image, + Name = "无", + Priority = i, + })); + + /// + /// 自动配置符文天赋 + /// + [ObservableProperty] + private bool _autoPerk; + + /// + /// 自动选择 + /// + [ObservableProperty] + private bool _autoAcceptSelect; + /// + /// 自动选择联动组件显隐 + /// + [ObservableProperty] + private Visibility _autoAcceptSelectHeroVisibility = Visibility.Hidden; + + /// + /// 自动选择延迟时间 + /// + [ObservableProperty] private int _autoAcceptSelectDelayTime; + /// + /// 自动根据列表随机选用 + /// + [ObservableProperty] + private bool _autoAcceptSelectRandom; + + + /// + /// 非排位模式,自动优先选择对应位置英雄 + /// + [ObservableProperty] + private int _unRankedSelectPosition; + + /// + /// 位置信息 + /// + [ObservableProperty] + private static List _positions = Global.Positions; + + /// + /// 自动选用英雄列表 + /// + [ObservableProperty] + private ObservableCollection _autoAcceptSelectHeroGroups = new(_positions.Select( + p => new SelectHeroGroup + { + HeroPosition = p, + SelectHeroes = new ObservableCollection(Enumerable.Range(0, 3).Select(i => new SelectHero + { + ChampionId = -1, + HeadPortrait = p.Image, + Name = "无", + Priority = i, + Portrait = p.Portrait, + Type = ConfigKeyEnum.AutoSelect, + })) + })); + /// + /// 设置头像或背景id值 + /// + [ObservableProperty] + private string _profileIconId; + + /// + /// 自动禁用或选用英雄状态值 + /// 0、1:禁用中、2:选用中 + /// + private static int _autoHeroState; + + private static readonly object AutoHeroLock = new(); + + private readonly ILcuService _lcuService; + private readonly IDbService _dbService; + private readonly IWindowService _windowService; + public SettingViewModel() + { + _lcuService = Ioc.Default.GetService()!; + _dbService = Ioc.Default.GetService()!; + _windowService = Ioc.Default.GetService()!; + _autoAcceptBanHeroes.CollectionChanged += SaveSelectHeroesChanged!; + foreach (var selectHeroGroup in _autoAcceptSelectHeroGroups) + { + selectHeroGroup.SelectHeroes.CollectionChanged += SaveSelectHeroesChanged!; + } + } + + + private void SessionActionBing(bool value, ConfigKeyEnum configKey) + { + + int delayTime = 0; + Visibility visibility = value ? Visibility.Visible : Visibility.Collapsed; + switch (configKey) + { + case ConfigKeyEnum.AutoAccept: + delayTime = AutoAcceptDelayTime; + AutoAcceptVisibility = visibility; + LolConnect.ManageEventAction(value, SubscribeEventUri.GameReadyCheck, AutoAcceptHandle!); + break; + case ConfigKeyEnum.AutoBan: + delayTime = AutoAcceptBanDelayTime; + AutoAcceptBanHeroVisibility = visibility; + LolConnect.ManageEventAction(value, SubscribeEventUri.GameSessionChamp, AutoAcceptBanHandleAsync!); + break; + case ConfigKeyEnum.AutoSelect: + delayTime = AutoAcceptSelectDelayTime; + AutoAcceptSelectHeroVisibility = visibility; + LolConnect.ManageEventAction(value, SubscribeEventUri.GameSessionChamp, AutoAcceptSelectHandleAsync!); + break; + case ConfigKeyEnum.AutoPerk: + LolConnect.ManageEventAction(value, SubscribeEventUri.SummonersChamp, AutoPerkSetHandleAsync!); + break; + case ConfigKeyEnum.AutoBanRandom: + case ConfigKeyEnum.AutoSelectRandom: + break; + default: + throw new ArgumentOutOfRangeException(nameof(configKey), configKey, null); + } + _dbService.InsertOrUpdate(new Config + { + Key = configKey, + Value = value.ToString(), + DelayTime = delayTime + }); + } + + + #region 自动接受对局 + + partial void OnAutoAcceptChanged(bool value) => SessionActionBing(value, ConfigKeyEnum.AutoAccept); + + partial void OnAutoAcceptDelayTimeChanged(int value) => _dbService.UpdateConfigDelayTime(ConfigKeyEnum.AutoAccept, value); + + private void AutoAcceptHandle(JToken gameFlow, string uri, string type) + { + ReadyCheckMessage? message = gameFlow.ToObject(); + if (message == null) + return; + if (string.Compare(message.PlayerResponse, "None", StringComparison.OrdinalIgnoreCase) != 0) + return; + if (!AutoAccept || message.Timer != AutoAcceptDelayTime) + return; + _ = _lcuService.TeamBuilderReadyCheckAsync().Result; + + //重置选择状态 + _autoHeroState = 0; + } + #endregion + + #region 自动禁用或选择英雄 + /// + /// 自动禁用英雄 + /// + /// + partial void OnAutoAcceptBanChanged(bool value) => SessionActionBing(value, ConfigKeyEnum.AutoBan); + partial void OnAutoAcceptBanDelayTimeChanged(int value) => _dbService.UpdateConfigDelayTime(ConfigKeyEnum.AutoBan, value); + partial void OnAutoAcceptBanRandomChanged(bool value) => SessionActionBing(value, ConfigKeyEnum.AutoBanRandom); + /// + /// 禁用英雄处理 + /// + /// + private void AutoAcceptBanHandleAsync(JToken gameFlow, string uri, string type) => AutoAcceptHeroesHandleAsync(gameFlow, ConfigKeyEnum.AutoBan); + + /// + /// 自动配置天赋符文 + /// + /// + partial void OnAutoPerkChanged(bool value) => SessionActionBing(value, ConfigKeyEnum.AutoPerk); + + /// + /// 自动选择英雄 + /// + /// + partial void OnAutoAcceptSelectChanged(bool value) => SessionActionBing(value, ConfigKeyEnum.AutoSelect); + partial void OnAutoAcceptSelectDelayTimeChanged(int value) => _dbService.UpdateConfigDelayTime(ConfigKeyEnum.AutoSelect, value); + partial void OnAutoAcceptSelectRandomChanged(bool value) => SessionActionBing(value, ConfigKeyEnum.AutoSelectRandom); + /// + /// 非排位模式,位置设置 + /// + /// + partial void OnUnRankedSelectPositionChanged(int value) + { + _dbService.InsertOrUpdate(new Config + { + Key = ConfigKeyEnum.UnRankedSelectPosition, + Value = value.ToString(), + }); + } + /// + /// 选用英雄处理 + /// + /// + private void AutoAcceptSelectHandleAsync(JToken gameFlow, string uri, string type) => AutoAcceptHeroesHandleAsync(gameFlow, ConfigKeyEnum.AutoSelect); + + + /// + /// 保存英雄选择信息 + /// + /// + /// + private void SaveSelectHeroesChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) + { + SelectHero newValue = notifyCollectionChangedEventArgs.NewItems!.OfType().First(); + _dbService.InsertOrUpdate(newValue); + } + + /// + /// 自动禁用或选择英雄回调处理 + /// + /// + /// + private async ValueTask AutoAcceptHeroesHandleAsync(JToken gameFlow, ConfigKeyEnum configKey) + { + //NORMAL 匹配 + //RANKED_SOLO_5x5 单双排 + //RANKED_FLEX_SR 组排 + //ARAM_UNRANKED_5x5 大乱斗5v5 + //URF 无限火力 + //BOT 人机 + //PRACTICETOOL 自定义 + ChampSelectMessage? message = gameFlow.ToObject(); + if (message == null) + return; + await AutoAcceptBanPackHeroAsync(message, configKey); + } + /// + /// 自动禁用或选择英雄 + /// 预选:15s,禁用、选用:30s + /// + /// + /// + /// + private async ValueTask AutoAcceptBanPackHeroAsync(ChampSelectMessage champ, ConfigKeyEnum sessionType) + { + //当前会话类型 + //NORMAL + //Ban:禁用 + //Pick:选择 + if (champ?.Actions == null) + return; + string type = sessionType == ConfigKeyEnum.AutoBan ? "ban" : "pick"; + ActionsItem? action = champ.Actions + .SelectMany(p => p).Where(p => p.ActorCellId == champ.LocalPlayerCellId) + .FirstOrDefault(p => p.Type == type); + if (action is not { IsInProgress: true }) + return; + int sessionTypeInt = (int)sessionType; + IEnumerable selectHeroes = _dbService.GetAll(p => p.Type == sessionType) + .Where(p => p.ChampionId >= 0) + .ToList(); + if (sessionTypeInt == _autoHeroState || !selectHeroes.Any()) + return; + //是否随机禁用列表英雄 + bool isRandom; + //延迟选择时间,秒 + int delayTime; + switch (sessionType) + { + case ConfigKeyEnum.AutoBan: + isRandom = AutoAcceptBanRandom; + delayTime = AutoAcceptBanDelayTime; + break; + case ConfigKeyEnum.AutoSelect: + isRandom = AutoAcceptSelectRandom; + delayTime = AutoAcceptSelectDelayTime; + //获取位置信息,根据位置信息选择英雄 + string position = Positions[UnRankedSelectPosition].Portrait; + if (champ.MyTeam != null) + { + TeamInfo? myInfo = champ.MyTeam.FirstOrDefault(p => p.CellId == champ.LocalPlayerCellId); + if (myInfo != null) + position = myInfo.AssignedPosition; + } + selectHeroes = selectHeroes.Where(p => p.Portrait == position); + break; + default: + return; + } + selectHeroes = isRandom ? selectHeroes.OrderBy(_ => Random.Shared.Next()) : selectHeroes.OrderBy(p => p.Priority); + lock (AutoHeroLock) + { + if (sessionTypeInt == _autoHeroState) + return; + Thread.Sleep(delayTime * 1000); + if (sessionType == ConfigKeyEnum.AutoBan && !AutoAcceptBan || sessionType == ConfigKeyEnum.AutoSelect && !AutoAcceptSelect) + return; + foreach (SelectHero selectSessionHero in selectHeroes) + { + ApiResponse result = _lcuService.ChampSelectSessionActionsAsync(action.Id, new SessionActionsRequest(selectSessionHero.ChampionId, action.Type)).Result; + if (result.StatusCode != HttpStatusCode.OK) + continue; + _autoHeroState = sessionTypeInt; + break; + } + } + await Task.CompletedTask; + } + + #endregion + + #region 自动配置符文信息 + + /// + /// 选用英雄配置符文信息 + /// + /// + private void AutoPerkSetHandleAsync(JToken gameFlow, string uri, string type) + { + SelectSummonersMessage? message = gameFlow.ToObject(); + if (!AutoPerk || message == null || Global.LocalPlayerCellId != message.CellId) + return; + SetPerkPage(message.ChampionId); + Global.LocalPlayerCellId = null; + } + + /// + /// 设置符文页 + /// + /// + private void SetPerkPage(int championId) + { + HeroRune? heroRune = _dbService.Get(p => p.ChampionId == championId); + if (heroRune == null || string.IsNullOrWhiteSpace(heroRune.RuneJson)) + return; + //获取符文信息 + ApiResponse getPerkResponse = _lcuService.GetPerkCurrentPageAsync().Result; + long? perkPageId = getPerkResponse?.Content?.Id; + //新符文页 + Dictionary? selectRune = JsonConvert.DeserializeObject>(heroRune.RuneJson); + if (selectRune == null) + return; + PerkPageRequest request = new PerkPageRequest() + { + Name = heroRune.Name, + SelectedPerkIds = selectRune.SelectMany(p => p.Value).Where(p => p > 0).ToList() + }; + foreach (var item in selectRune.Where(item => item.Key != 2)) + { + switch (item.Value.Length) + { + case 4: + request.PrimaryStyleId = item.Key; + break; + case 3: + request.SubStyleId = item.Key; + break; + } + } + _ = perkPageId == null ? _lcuService.CreatePerkPageAsync(request).Result : _lcuService.UpdatePerkPageAsync(perkPageId.Value, request).Result; + } + + #endregion + + /// + /// 重置客户端窗口 + /// + public void ResetClientWindow() + { + _windowService.SetWindowsSize(1280, 720); + } +} diff --git a/src/LOL.Assist.App/Views/Controls/DelayTime.xaml b/src/LOL.Assist.App/Views/Controls/DelayTime.xaml new file mode 100644 index 0000000..335be93 --- /dev/null +++ b/src/LOL.Assist.App/Views/Controls/DelayTime.xaml @@ -0,0 +1,22 @@ + + + + diff --git a/src/LOL.Assist.App/Views/Controls/DelayTime.xaml.cs b/src/LOL.Assist.App/Views/Controls/DelayTime.xaml.cs new file mode 100644 index 0000000..1760a80 --- /dev/null +++ b/src/LOL.Assist.App/Views/Controls/DelayTime.xaml.cs @@ -0,0 +1,53 @@ +using System.Windows; + +namespace LOL.Assist.App.Views.Controls +{ + /// + /// DelayTime.xaml 的交互逻辑 + /// + public partial class DelayTime + { + public DelayTime() + { + InitializeComponent(); + DelayTimePanel.DataContext = this; + } + public int Value + { + get => (int)GetValue(ValueProperty); + set => SetValue(ValueProperty, value); + } + + // Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc... + public static readonly DependencyProperty ValueProperty = + DependencyProperty.Register(nameof(Value), typeof(int), typeof(DelayTime), new PropertyMetadata(0)); + + + + public int MaxValue + { + get => (int)GetValue(MaxValueProperty); + set => SetValue(MaxValueProperty, value); + } + + // Using a DependencyProperty as the backing store for MaxValue. This enables animation, styling, binding, etc... + public static readonly DependencyProperty MaxValueProperty = + DependencyProperty.Register(nameof(MaxValue), typeof(int), typeof(DelayTime), new PropertyMetadata(0)); + + + + public int MinValue + { + get => (int)GetValue(MinValueProperty); + set => SetValue(MinValueProperty, value); + } + + // Using a DependencyProperty as the backing store for MinValue. This enables animation, styling, binding, etc... + public static readonly DependencyProperty MinValueProperty = + DependencyProperty.Register(nameof(MinValue), typeof(int), typeof(DelayTime), new PropertyMetadata(0)); + + + + + } +} diff --git a/src/LOL.Assist.App/Views/Controls/HeroControl.xaml b/src/LOL.Assist.App/Views/Controls/HeroControl.xaml new file mode 100644 index 0000000..4cb796f --- /dev/null +++ b/src/LOL.Assist.App/Views/Controls/HeroControl.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/src/LOL.Assist.App/Views/Controls/HeroControl.xaml.cs b/src/LOL.Assist.App/Views/Controls/HeroControl.xaml.cs new file mode 100644 index 0000000..8c80039 --- /dev/null +++ b/src/LOL.Assist.App/Views/Controls/HeroControl.xaml.cs @@ -0,0 +1,85 @@ +using System.Windows; +using System.Windows.Media; + +namespace LOL.Assist.App.Views.Controls +{ + /// + /// HeroControl.xaml 的交互逻辑 + /// + public partial class HeroControl + { + public HeroControl() + { + InitializeComponent(); + HeroPhotoRoot.DataContext = this; + } + + + public ImageSource Image + { + get => (ImageSource)GetValue(ImageProperty); + set => SetValue(ImageProperty, value); + } + + public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(nameof(Image), + typeof(ImageSource), + typeof(HeroControl), + new PropertyMetadata(null)); + + /// + /// 标题 + /// + public string Title + { + get => (string)GetValue(TitleProperty); + set => SetValue(TitleProperty, value); + } + + public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), + typeof(string), + typeof(HeroControl), + new PropertyMetadata(string.Empty)); + + /// + /// 英雄id + /// + public int ChampionId + { + get => (int)GetValue(ChampionIdProperty); + set => SetValue(ChampionIdProperty, value); + } + + public static readonly DependencyProperty ChampionIdProperty = DependencyProperty.Register(nameof(ChampionId), + typeof(int), + typeof(HeroControl), + new PropertyMetadata(0)); + + /// + /// 优先权限 + /// + public int Priority + { + get => (int)GetValue(PriorityProperty); + set => SetValue(PriorityProperty, value); + } + + public static readonly DependencyProperty PriorityProperty = DependencyProperty.Register(nameof(Priority), + typeof(int), + typeof(HeroControl), + new PropertyMetadata(0)); + + /// + /// 位置信息 + /// + public string Position + { + get => (string)GetValue(PositionProperty); + set => SetValue(PositionProperty, value); + } + + public static readonly DependencyProperty PositionProperty = DependencyProperty.Register(nameof(Position), + typeof(string), + typeof(HeroControl), + new PropertyMetadata(string.Empty)); + } +} diff --git a/src/LOL.Assist.App/Views/MainWindow.xaml b/src/LOL.Assist.App/Views/MainWindow.xaml new file mode 100644 index 0000000..565eaf1 --- /dev/null +++ b/src/LOL.Assist.App/Views/MainWindow.xaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/LOL.Assist.App/Views/MainWindow.xaml.cs b/src/LOL.Assist.App/Views/MainWindow.xaml.cs new file mode 100644 index 0000000..b1830d1 --- /dev/null +++ b/src/LOL.Assist.App/Views/MainWindow.xaml.cs @@ -0,0 +1,169 @@ +using System; +using CommunityToolkit.Mvvm.DependencyInjection; +using LOL.Assist.App.ViewModels; +using LOL.Assist.Core.DbModels; +using LOL.Assist.Core.Enums; +using LOL.Assist.Core.IServices; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; +using LOL.Assist.Core.Models; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; +using Wpf.Ui.Mvvm.Contracts; +using LOL.Assist.Core; +using Newtonsoft.Json.Linq; + +namespace LOL.Assist.App.Views +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : UiWindow + { + private readonly IThemeService _themeService; + private bool _initialized; + + public MainWindow() + { + InitializeComponent(); + + _themeService = Ioc.Default.GetService()!; + SetThemeLabel(); + Loaded += (_, _) => Initialize(); + LolConnect.ConnectNotificationAction += SetWindowLocation; + } + + private void Initialize() + { + if (_initialized) + return; + + _initialized = true; + Loading.Visibility = Visibility.Visible; + FramePage.Visibility = Visibility.Hidden; + Task.Run(async () => + { + IDbService dbService = Ioc.Default.GetService()!; + IGameService gameService = Ioc.Default.GetService()!; + ILOLService lolService = Ioc.Default.GetService()!; + //加载默认监听事件 + LolConnect.ManageEventAction(true, SubscribeEventUri.GameSessionChamp, Global.GameSessionHandle!); + //加载全局数据 + Global.Heroes = (await gameService.GetHeroListAsync()).Hero; + string heroPosition = await lolService.GetHeroPositionAsync(); + if (!string.IsNullOrWhiteSpace(heroPosition)) + { + string heroPositionJson = heroPosition.Split('=', ';')[1]; + Dictionary? heroPositionRecommend = JObject.Parse(heroPositionJson)["list"]?.ToObject>(); + if (heroPositionRecommend != null) + Global.Heroes.ForEach(p => p.PositionRecommend = heroPositionRecommend.GetValueOrDefault(p.HeroId) ?? new HeroPositionRecommend()); + } + Global.Runes = (await gameService.GetRuneListAsync()).Rune.Select(p => + { + p.Value.Id = p.Key; + return p.Value; + }).ToList(); + + //加载配置内容 + SettingViewModel settingsViewModel = Ioc.Default.GetService()!; + IList configs = dbService.GetAll(); + foreach (var config in configs) + { + switch (config.Key) + { + case ConfigKeyEnum.AutoAccept: + settingsViewModel.AutoAccept = bool.Parse(config.Value); + settingsViewModel.AutoAcceptDelayTime = config.DelayTime; + break; + case ConfigKeyEnum.AutoBan: + settingsViewModel.AutoAcceptBan = bool.Parse(config.Value); + settingsViewModel.AutoAcceptBanDelayTime = config.DelayTime; + IList selectSessionBanHeroes = dbService.GetAll(p => p.Type == ConfigKeyEnum.AutoBan); + foreach (SelectHero selectHero in selectSessionBanHeroes.OrderBy(p => p.Priority)) + { + await Dispatcher.InvokeAsync(() => + { + settingsViewModel.AutoAcceptBanHeroes[selectHero.Priority] = selectHero; + }); + } + break; + case ConfigKeyEnum.AutoSelect: + settingsViewModel.AutoAcceptSelect = bool.Parse(config.Value); + settingsViewModel.AutoAcceptSelectDelayTime = config.DelayTime; + IList selectSessionSelectHeroes = dbService.GetAll(p => p.Type == ConfigKeyEnum.AutoSelect); + foreach (var selectHeroGroup in selectSessionSelectHeroes.GroupBy(p => p.Portrait)) + { + SelectHeroGroup? heroGroup = settingsViewModel.AutoAcceptSelectHeroGroups + .FirstOrDefault(p => p.HeroPosition.Portrait == selectHeroGroup.Key); + if (heroGroup == null) + continue; + await Dispatcher.InvokeAsync(() => + { + selectHeroGroup.ToList().ForEach(selectHero => + heroGroup.SelectHeroes[selectHero.Priority] = selectHero); + }); + + } + break; + case ConfigKeyEnum.AutoBanRandom: + settingsViewModel.AutoAcceptBanRandom = bool.Parse(config.Value); + break; + case ConfigKeyEnum.AutoSelectRandom: + settingsViewModel.AutoAcceptSelectRandom = bool.Parse(config.Value); + break; + case ConfigKeyEnum.UnRankedSelectPosition: + settingsViewModel.UnRankedSelectPosition = int.Parse(config.Value); + break; + case ConfigKeyEnum.AutoPerk: + settingsViewModel.AutoPerk = bool.Parse(config.Value); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + await Dispatcher.InvokeAsync(() => + { + Loading.Visibility = Visibility.Hidden; + FramePage.Visibility = Visibility.Visible; + }); + + return true; + }); + } + + /// + /// 设置窗口位置 + /// + private void SetWindowLocation() + { + IWindowService windowService = Ioc.Default.GetService()!; + var rect = windowService.GetWindowsRectLocation(); + if (rect == null) + return; + Dispatcher.Invoke(() => + { + Left = rect.Value.Left - Width; + Top = rect.Value.Top; + }); + } + private void NotifyBarExit_Click(object sender, RoutedEventArgs e) + { + Application.Current.Shutdown(); + NotifyMenuBar = null; + } + + private void ButtonTheme_OnClick(object sender, RoutedEventArgs e) + { + _themeService.SetTheme(_themeService.GetTheme() == ThemeType.Dark ? ThemeType.Light : ThemeType.Dark); + SetThemeLabel(); + } + + private void SetThemeLabel(ThemeType? themeType = null) + { + themeType ??= _themeService.GetTheme(); + // ThemeLabel.Content = themeType == ThemeType.Dark ? "黑暗" : "明亮"; + } + } +} diff --git a/src/LOL.Assist.App/Views/Pages/RunePage.xaml b/src/LOL.Assist.App/Views/Pages/RunePage.xaml new file mode 100644 index 0000000..c2cfcd4 --- /dev/null +++ b/src/LOL.Assist.App/Views/Pages/RunePage.xaml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + +