diff --git a/.all-contributorsrc b/.all-contributorsrc index e8b32ea..1361be4 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1,103 +1,103 @@ -{ - "files": [ - "README.md" - ], - "imageSize": 100, - "contributorsPerLine": 7, - "contributorsSortAlphabetically": false, - "badgeTemplate": "[![All Contributors](https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square)](#contributors)", - "skipCi": true, - "contributors": [ - { - "login": "axsLeaf", - "name": "Willow", - "avatar_url": "https://avatars.githubusercontent.com/u/1693101?v=4", - "profile": "https://leafhub.dev", - "contributions": [ - "code", - "financial" - ] - }, - { - "login": "EndGameGl", - "name": "MeGl", - "avatar_url": "https://avatars.githubusercontent.com/u/54992889?v=4", - "profile": "https://github.com/EndGameGl", - "contributions": [ - "code", - "mentoring" - ] - }, - { - "login": "Zempp", - "name": "Zempp", - "avatar_url": "https://avatars.githubusercontent.com/u/90584529?v=4", - "profile": "https://www.bungie.net/7/en/User/Profile/254/10910315?bgn=Zempp", - "contributions": [ - "data" - ] - }, - { - "login": "calmqq", - "name": "calmqq", - "avatar_url": "https://avatars.githubusercontent.com/u/49577234?v=4", - "profile": "https://github.com/calmqq", - "contributions": [ - "data" - ] - }, - { - "login": "TheLastJoaquin", - "name": "TheLastJoaquin", - "avatar_url": "https://avatars.githubusercontent.com/u/108595663?v=4", - "profile": "https://github.com/TheLastJoaquin", - "contributions": [ - "data" - ] - }, - { - "login": "Subhaven", - "name": "Subhaven", - "avatar_url": "https://avatars.githubusercontent.com/u/30436380?v=4", - "profile": "https://github.com/Subhaven", - "contributions": [ - "design" - ] - }, - { - "login": "quiffboy", - "name": "Barry Briggs", - "avatar_url": "https://avatars.githubusercontent.com/u/11392094?v=4", - "profile": "https://github.com/quiffboy", - "contributions": [ - "financial" - ] - }, - { - "login": "gothfemme", - "name": "Kat Michaela", - "avatar_url": "https://avatars.githubusercontent.com/u/42180996?v=4", - "profile": "http://gothfem.me", - "contributions": [ - "tool", - "mentoring" - ] - }, - { - "login": "camohiddendj", - "name": "camo", - "avatar_url": "https://avatars.githubusercontent.com/u/11087140?v=4", - "profile": "https://d2checkpoint.com/", - "contributions": [ - "financial", - "infra" - ] - } - ], - "projectName": "Bot-Frontend", - "projectOwner": "devFelicity", - "repoType": "github", - "repoHost": "https://github.com", - "commitType": "docs", - "commitConvention": "angular" -} +{ + "files": [ + "README.md" + ], + "imageSize": 100, + "contributorsPerLine": 7, + "contributorsSortAlphabetically": false, + "badgeTemplate": "[![All Contributors](https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square)](#contributors)", + "skipCi": true, + "contributors": [ + { + "login": "axsLeaf", + "name": "Willow", + "avatar_url": "https://avatars.githubusercontent.com/u/1693101?v=4", + "profile": "https://leafhub.dev", + "contributions": [ + "code", + "financial" + ] + }, + { + "login": "EndGameGl", + "name": "MeGl", + "avatar_url": "https://avatars.githubusercontent.com/u/54992889?v=4", + "profile": "https://github.com/EndGameGl", + "contributions": [ + "code", + "mentoring" + ] + }, + { + "login": "Zempp", + "name": "Zempp", + "avatar_url": "https://avatars.githubusercontent.com/u/90584529?v=4", + "profile": "https://www.bungie.net/7/en/User/Profile/254/10910315?bgn=Zempp", + "contributions": [ + "data" + ] + }, + { + "login": "calmqq", + "name": "calmqq", + "avatar_url": "https://avatars.githubusercontent.com/u/49577234?v=4", + "profile": "https://github.com/calmqq", + "contributions": [ + "data" + ] + }, + { + "login": "TheLastJoaquin", + "name": "TheLastJoaquin", + "avatar_url": "https://avatars.githubusercontent.com/u/108595663?v=4", + "profile": "https://github.com/TheLastJoaquin", + "contributions": [ + "data" + ] + }, + { + "login": "Subhaven", + "name": "Subhaven", + "avatar_url": "https://avatars.githubusercontent.com/u/30436380?v=4", + "profile": "https://github.com/Subhaven", + "contributions": [ + "design" + ] + }, + { + "login": "quiffboy", + "name": "Barry Briggs", + "avatar_url": "https://avatars.githubusercontent.com/u/11392094?v=4", + "profile": "https://github.com/quiffboy", + "contributions": [ + "financial" + ] + }, + { + "login": "gothfemme", + "name": "Kat Michaela", + "avatar_url": "https://avatars.githubusercontent.com/u/42180996?v=4", + "profile": "http://gothfem.me", + "contributions": [ + "tool", + "mentoring" + ] + }, + { + "login": "camohiddendj", + "name": "camo", + "avatar_url": "https://avatars.githubusercontent.com/u/11087140?v=4", + "profile": "https://d2checkpoint.com/", + "contributions": [ + "financial", + "infra" + ] + } + ], + "projectName": "Bot-Frontend", + "projectOwner": "devFelicity", + "repoType": "github", + "repoHost": "https://github.com", + "commitType": "docs", + "commitConvention": "angular" +} diff --git a/.dockerignore b/.dockerignore index 3729ff0..bdca33b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,25 +1,25 @@ -**/.classpath -**/.dockerignore -**/.env -**/.git -**/.gitignore -**/.project -**/.settings -**/.toolstarget -**/.vs -**/.vscode -**/*.*proj.user -**/*.dbmdl -**/*.jfm -**/azds.yaml -**/bin -**/charts -**/docker-compose* -**/Dockerfile* -**/node_modules -**/npm-debug.log -**/obj -**/secrets.dev.yaml -**/values.dev.yaml -LICENSE +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE README.md \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 836511f..664e8e8 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,5 +1,5 @@ -# These are supported funding model platforms - -ko_fi: mooniegz -github: mooniegz -custom: "https://pay.moons.bio" +# These are supported funding model platforms + +ko_fi: mooniegz +github: mooniegz +custom: "https://pay.moons.bio" diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 7895bfa..aa150c9 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,57 +1,57 @@ ---- -name: Bug Report -about: Tell us about a bug. -title: '' -labels: bug -assignees: axsLeaf - ---- - - - - - -**Bug Description**: - - - - - -**Steps To Reproduce**: - - - - - -**Expected Behaviour**: - - - - - -**Additional Information**: - - - - - -- [ ] I **decline** to being added to the Contributors list. - +--- +name: Bug Report +about: Tell us about a bug. +title: '' +labels: bug +assignees: axsLeaf + +--- + + + + + +**Bug Description**: + + + + + +**Steps To Reproduce**: + + + + + +**Expected Behaviour**: + + + + + +**Additional Information**: + + + + + +- [ ] I **decline** to being added to the Contributors list. + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index ffee444..e315913 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,55 +1,55 @@ ---- -name: Feature Request -about: Suggest a feature or command. -title: '' -labels: enhancement -assignees: axsLeaf - ---- - - - - - -**Feature Description**: - - - -**Alternatives**: - - - - - -**Reasoning**: - - - - - -**Additional Information**: - - - - - -- [ ] I **decline** to being added to the Contributors list. - +--- +name: Feature Request +about: Suggest a feature or command. +title: '' +labels: enhancement +assignees: axsLeaf + +--- + + + + + +**Feature Description**: + + + +**Alternatives**: + + + + + +**Reasoning**: + + + + + +**Additional Information**: + + + + + +- [ ] I **decline** to being added to the Contributors list. + \ No newline at end of file diff --git a/.github/changelog-ci-config.yml b/.github/changelog-ci-config.yml index aadef4a..2a6eb80 100644 --- a/.github/changelog-ci-config.yml +++ b/.github/changelog-ci-config.yml @@ -1,30 +1,30 @@ -changelog_type: 'commit_message' # or 'pull_request' -header_prefix: 'Version:' -commit_changelog: true -comment_changelog: true -include_unlabeled_changes: true -unlabeled_group_title: 'Unlabeled Changes' -pull_request_title_regex: '^Release' -version_regex: 'v?([0-9]{1,2})+[.]+([0-9]{1,2})+[.]+([0-9]{1,2})\s\(\d{1,2}-\d{1,2}-\d{4}\)' -exclude_labels: - - bot - - dependabot - - dependencies - - ci -group_config: - - title: Bug Fixes - labels: - - bug - - bugfix - - title: Code Improvements - labels: - - improvements - - enhancement - - title: New Features - labels: - - feature - - title: Documentation Updates - labels: - - docs - - documentation +changelog_type: 'commit_message' # or 'pull_request' +header_prefix: 'Version:' +commit_changelog: true +comment_changelog: true +include_unlabeled_changes: true +unlabeled_group_title: 'Unlabeled Changes' +pull_request_title_regex: '^Release' +version_regex: 'v?([0-9]{1,2})+[.]+([0-9]{1,2})+[.]+([0-9]{1,2})\s\(\d{1,2}-\d{1,2}-\d{4}\)' +exclude_labels: + - bot + - dependabot + - dependencies + - ci +group_config: + - title: Bug Fixes + labels: + - bug + - bugfix + - title: Code Improvements + labels: + - improvements + - enhancement + - title: New Features + labels: + - feature + - title: Documentation Updates + labels: + - docs + - documentation - doc \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 745e870..6af06ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,28 +1,28 @@ -name: Build Check - -on: - pull_request: - branches: - - main - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3.6.0 - - - name: Setup .NET - uses: actions/setup-dotnet@v3 - with: - dotnet-version: '6.0.x' - - - name: Restore dependencies - run: dotnet restore Felicity/Felicity.csproj - - - name: Build application - run: dotnet build Felicity/Felicity.csproj --configuration Release --no-restore - - - name: Check build status - run: dotnet build Felicity/Felicity.csproj --configuration Release --no-restore --no-incremental +name: Build Check + +on: + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3.6.0 + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '6.0.x' + + - name: Restore dependencies + run: dotnet restore Felicity/Felicity.csproj + + - name: Build application + run: dotnet build Felicity/Felicity.csproj --configuration Release --no-restore + + - name: Check build status + run: dotnet build Felicity/Felicity.csproj --configuration Release --no-restore --no-incremental diff --git a/.gitignore b/.gitignore index f6f7060..51fdb0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,211 +1,211 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml - -# 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 -## TODO: Comment the next line if you want to checkin your -## web deploy settings but do note that will include unencrypted -## passwords -#*.pubxml - -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Windows Azure Build Output -csx/ -*.build.csdef - -# Windows Store app package directory -AppPackages/ - -# 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/ -[Ss]tyle[Cc]op.* -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.publishsettings -node_modules/ -orleans.codegen.cs - -# 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 - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# LightSwitch generated files -GeneratedArtifacts/ -_Pvt_Extensions/ -ModelManifest.xml +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# 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 +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# 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/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.publishsettings +node_modules/ +orleans.codegen.cs + +# 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 + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f4fbc..138b69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,164 +1,164 @@ -# Version: v8.0.5 (27-06-2023) - -* [a2ea6ee](https://github.com/devFelicity/Bot-Frontend/commit/a2ea6eed2e5e2080f9d44c64c1230243bb596552): Update FUNDING.yml -* [3c84501](https://github.com/devFelicity/Bot-Frontend/commit/3c84501b77228d1b8a4faef8efab1c3979cd8804): ci(docker): update build actions -* [acc95d3](https://github.com/devFelicity/Bot-Frontend/commit/acc95d33cf078c3be25b495cf897f88f33c14e6f): Update publish.yml -* [5c34905](https://github.com/devFelicity/Bot-Frontend/commit/5c34905f6fa3f4e06e8ba27d63fad8e27ac9cac9): Update publish.yml -* [974baa7](https://github.com/devFelicity/Bot-Frontend/commit/974baa7e3765ec7f7942ef9da7ee798fd17f4816): Update publish.yml - - -# Version: v8.0.1 (21-06-2023) -* [eaae19a](https://github.com/devFelicity/Bot-Frontend/commit/eaae19aee0eebeed80cd5bdb625fbe9f2d8db505): docs(changelog): trim unwanted lines [skip ci] -* [b0fa1ad](https://github.com/devFelicity/Bot-Frontend/commit/b0fa1ad2cd85e33942a6f7cb8d04a04ae200ec5a): [Changelog CI] Add Changelog for Version v8.0.0 (21-06-2023) -* [c29bd1d](https://github.com/devFelicity/Bot-Frontend/commit/c29bd1d838fef56c6fcc18a2678467e6ffce5210): ci(changelog): update dependabot settings to be ignored -* [df18cdf](https://github.com/devFelicity/Bot-Frontend/commit/df18cdf2303a023c101defdab70ee34ba90e57e4): ci(changelog): force re-generation with new settings -* [2a3aa14](https://github.com/devFelicity/Bot-Frontend/commit/2a3aa147a41ab95044a16eab529a4a8b26bfdbf1): ci(changelog): trim unwanted lines -* [91426ae](https://github.com/devFelicity/Bot-Frontend/commit/91426ae235c83a447432bfd59400f3e1db6e46b9): [Changelog CI] Add Changelog for Version v8.0.0 (21-06-2023) -* [c127caa](https://github.com/devFelicity/Bot-Frontend/commit/c127caad2974686a2bf8fa1a7fd24eae9fb2f3c1): ci(changelog): remove auto-publisher (will re-add later if I don't forget) -* [e84dd70](https://github.com/devFelicity/Bot-Frontend/commit/e84dd7036ba1ae46788687688d9c21feb0aa2233): ci(changelog): typo in config file name -* [a31b2cd](https://github.com/devFelicity/Bot-Frontend/commit/a31b2cdc65e3288e255c0c69512de92ad85638f2): ci(changelog): delete changelog.md -* [c9d0e10](https://github.com/devFelicity/Bot-Frontend/commit/c9d0e104a7268ba841edbc92fb261d080155fc90): ci(changelog): remove old busted changelog CI -* [fa42235](https://github.com/devFelicity/Bot-Frontend/commit/fa422350f3421f99365d54022330c33aa44324be): feat(rollfinder): add support for new layout -* [4a94b22](https://github.com/devFelicity/Bot-Frontend/commit/4a94b228fcdf4e6899dee68afb680a0f4808c1fe): style(main): auto-cleanup -* [85c11cb](https://github.com/devFelicity/Bot-Frontend/commit/85c11cb6a004b33372399f38744939e1099d2bc2): Merge remote-tracking branch 'origin/develop' into develop -* [6014cc0](https://github.com/devFelicity/Bot-Frontend/commit/6014cc025d003694311c403d1f002d33ac142844): feat(debug): add WSL support and commitizen -* [f8ecc00](https://github.com/devFelicity/Bot-Frontend/commit/f8ecc004a6ac6e6b52c308536b8c4a165c139103): Bump Serilog from 2.12.0 to 3.0.0 -* [5da8076](https://github.com/devFelicity/Bot-Frontend/commit/5da807641c65b37c85be7f7f7b4c33e074a723f5): update changelog -* [afd40ae](https://github.com/devFelicity/Bot-Frontend/commit/afd40aed2d32eadc322da548c573097f6554ca18): add color to logging -* [9e32977](https://github.com/devFelicity/Bot-Frontend/commit/9e329776cf26b91055dd5a00d121d50dc100cc3c): String optimisations -* [a634ed7](https://github.com/devFelicity/Bot-Frontend/commit/a634ed7cda149e0291cd26169a377ee8c8f361a8): Bump DotNetBungieAPI from 2.10.0 to 2.11.0 -* [fd75996](https://github.com/devFelicity/Bot-Frontend/commit/fd75996c76208fcb0caebbb18089b6e0542bbca8): Bump Fergun.Interactive from 1.7.1 to 1.7.2 -* [01b340e](https://github.com/devFelicity/Bot-Frontend/commit/01b340e9c254d720fc01e7fdb399f421819f30d2): docs: update .all-contributorsrc [skip ci] -* [38f0e91](https://github.com/devFelicity/Bot-Frontend/commit/38f0e916bee4937ab246505a64528983d8186f70): docs: update README.md [skip ci] -* [ee135b9](https://github.com/devFelicity/Bot-Frontend/commit/ee135b944a5243139a62f98073b64c5465282d28): Fix up readme -* [66a74b0](https://github.com/devFelicity/Bot-Frontend/commit/66a74b09c861367bd2521e55717ef19b5cc56c3f): Bump Sentry.AspNetCore from 3.33.0 to 3.33.1 -* [78c73e1](https://github.com/devFelicity/Bot-Frontend/commit/78c73e16d1527b658da0e82387b81434045aa7de): Update .all-contributorsrc [skip ci] -* [6b7aab8](https://github.com/devFelicity/Bot-Frontend/commit/6b7aab8b39e73603ba32337e7dd2e335c424f0b3): Update README.md [skip ci] -* [a20f1fa](https://github.com/devFelicity/Bot-Frontend/commit/a20f1fa9f0a0ceb90c7a1c22c76d08ab1296c240): Bump Microsoft.EntityFrameworkCore from 7.0.5 to 7.0.7 -* [b384f0d](https://github.com/devFelicity/Bot-Frontend/commit/b384f0d6b14aef362501e22b1889c282ade8bcb8): Bump Sentry.Serilog from 3.33.0 to 3.33.1 -* [773ac97](https://github.com/devFelicity/Bot-Frontend/commit/773ac97b8c41b9d53c1b0bbd72fece4a4e828b62): Fix LW weapons not appearing in crafted -* [eeb1d2b](https://github.com/devFelicity/Bot-Frontend/commit/eeb1d2b0c2c197be0bdcaafe153451931fcc5cc2): update changelog -* [c71e3cb](https://github.com/devFelicity/Bot-Frontend/commit/c71e3cb7776ea0ddd80f54a9fc68b819cc800f3e): fix incorrect urls in /support -* [6aad3c5](https://github.com/devFelicity/Bot-Frontend/commit/6aad3c50d782efe84d588589ca5a04b9a7539ef1): fix dupe in crafted weapons -* [5c5726c](https://github.com/devFelicity/Bot-Frontend/commit/5c5726c8dbf08365e0210fe615cd06096b273a14): Update README.md [skip ci] -* [b11d536](https://github.com/devFelicity/Bot-Frontend/commit/b11d536fee872bb3ef3f0584df698c920b7ff7ab): Update FUNDING.yml [skip ci] -* [f9c57fb](https://github.com/devFelicity/Bot-Frontend/commit/f9c57fb44edbaecc8caf0edd9a3a289ca62ae8cc): push changelog -* [7c141bb](https://github.com/devFelicity/Bot-Frontend/commit/7c141bb90c62a43cdab4b5b3f74d2cafe0a3b57e): cleanup -* [f10c602](https://github.com/devFelicity/Bot-Frontend/commit/f10c602c389e93ef8a8b7abade07413a564edac2): Remove redundant code -* [abb0d34](https://github.com/devFelicity/Bot-Frontend/commit/abb0d34ced01dcfe8f25982e0a1f3224702fea33): Re-add showAll on /recipes -* [cb6c690](https://github.com/devFelicity/Bot-Frontend/commit/cb6c6905d11c0227435a9e42625d3ec08b366725): correct Ada-1 description -* [5a07114](https://github.com/devFelicity/Bot-Frontend/commit/5a07114340c9628518a33fef886f1cc7924cc30b): Added count to rarest emblems -* [04e06b3](https://github.com/devFelicity/Bot-Frontend/commit/04e06b3de6bb6f1e303d75501d4c84b5fabaf4be): missed link change -* [ad4f3bb](https://github.com/devFelicity/Bot-Frontend/commit/ad4f3bb29326cdcaa80c6a4b929762abd798d9d1): bump dependencies -* [099c2f2](https://github.com/devFelicity/Bot-Frontend/commit/099c2f29487dc8b06bbbd697c140dffd99f0ce1c): add self-hosted assets -* [cb0275e](https://github.com/devFelicity/Bot-Frontend/commit/cb0275e5cbe446e2c2f9357cba4b774d054c61e4): add support message -* [7d886f8](https://github.com/devFelicity/Bot-Frontend/commit/7d886f8163de306f98f1584f7f6b1fcb7ef9d797): added GotD loot table -* [ebe4ab3](https://github.com/devFelicity/Bot-Frontend/commit/ebe4ab34f9a5ec17ed9b811dd107a655b5cc0e7b): Fix new version issues -* [a633f18](https://github.com/devFelicity/Bot-Frontend/commit/a633f18aa5f2489439e322d5bb9d2abffe9bf51b): update changelog [skip ci] -* [724494d](https://github.com/devFelicity/Bot-Frontend/commit/724494db4572160030ee939a798f9a4be20cc7f8): fix downgrade issue -* [07c9ec2](https://github.com/devFelicity/Bot-Frontend/commit/07c9ec2067ec325230f0e088bad5cd943aa62633): Bump DotNetBungieAPI from 2.9.0 to 2.10.0 -* [7b41abb](https://github.com/devFelicity/Bot-Frontend/commit/7b41abb0c6c284214c834574b4d83030f07cea35): Update dependabot.yml [skip-ci] -* [ddafacd](https://github.com/devFelicity/Bot-Frontend/commit/ddafacd171b26c0e6e08e359b25d2523b15d17de): docs: update .all-contributorsrc [skip ci] -* [18caba9](https://github.com/devFelicity/Bot-Frontend/commit/18caba9f802b1e5239e134120c2e8d835f00d205): docs: update README.md [skip ci] -* [1405d98](https://github.com/devFelicity/Bot-Frontend/commit/1405d98adaf4704139ebce63ef66819542fd69f3): Update .all-contributorsrc -* [cce0775](https://github.com/devFelicity/Bot-Frontend/commit/cce0775218a1acda390a63132b958a8da1dd7cd4): hopefully fixes cpu loop -* [9a3c95c](https://github.com/devFelicity/Bot-Frontend/commit/9a3c95c2796e84abad2aa6dd9c73660f650bcdc4): forgor changelog -* [0c71112](https://github.com/devFelicity/Bot-Frontend/commit/0c71112609df879e795f0064118fd6384e101602): Update to new auth url (also using as test) -* [079fc25](https://github.com/devFelicity/Bot-Frontend/commit/079fc251e39d528676b7cf974e627c38ff8df4b6): use jq to make a payload -* [f598f0d](https://github.com/devFelicity/Bot-Frontend/commit/f598f0d47c7b9e1fc7e224d99ee2c3c6b9fdd47c): attempt 412323234 at getting commit list to work -* [f2eb7fa](https://github.com/devFelicity/Bot-Frontend/commit/f2eb7fa4f4aa9b3025f45e4edabd299700d239fd): quote marks are weird -* [18676b9](https://github.com/devFelicity/Bot-Frontend/commit/18676b9394d75a9132a667367e3e07020ca77820): fix pr update json -* [8a01efa](https://github.com/devFelicity/Bot-Frontend/commit/8a01efa9e407a02e523013b605bbed913de55cde): Update github action -* [33ed80f](https://github.com/devFelicity/Bot-Frontend/commit/33ed80f313e8159c4c5dda3b22bad0004eb1c0e0): Revert "Update github action" -* [6768cdb](https://github.com/devFelicity/Bot-Frontend/commit/6768cdb3f6980301038ee3e4cbf7eefa9d63a7e1): Update github action -* [900d729](https://github.com/devFelicity/Bot-Frontend/commit/900d729c5b9df70a8caa56da2840f52a37159186): Update changelog -* [12d0910](https://github.com/devFelicity/Bot-Frontend/commit/12d091081a7327e6bda488b401f45a70c5e2813a): add paginator to /recipes -* [6db0329](https://github.com/devFelicity/Bot-Frontend/commit/6db0329e418839fa7b0102ec248d338159eb7bce): cleanup code -* [600795e](https://github.com/devFelicity/Bot-Frontend/commit/600795edf1ef7389d843ddffd8e700c7b8bafc27): add vendor json for debugging -* [9d599cd](https://github.com/devFelicity/Bot-Frontend/commit/9d599cdfa731366634d6789227fd4292d59e4f8d): prevent metrics crash and unrelated errors -* [5f3c037](https://github.com/devFelicity/Bot-Frontend/commit/5f3c037bf8dc892187a1e478188b28f55ea667ea): move embed color to constant -* [49d59ce](https://github.com/devFelicity/Bot-Frontend/commit/49d59ce3e0137fac385071591342c919db8d40e1): start ghosts of the deep loot table -* [e904e44](https://github.com/devFelicity/Bot-Frontend/commit/e904e44817e9251b78287f3aeda71a985b5f01c6): fix rank -* [9468cf0](https://github.com/devFelicity/Bot-Frontend/commit/9468cf0016d68fc6d67c06995f8042d7dcf6dc59): Update loot tables -* [af0dd1b](https://github.com/devFelicity/Bot-Frontend/commit/af0dd1b567c7bcf2c54c7e565be93d16d45f181e): prevents metrics error -* [ac55c60](https://github.com/devFelicity/Bot-Frontend/commit/ac55c608b486a311b29e747b2ba8a2662f202f01): Update dependencies -* [8b66e49](https://github.com/devFelicity/Bot-Frontend/commit/8b66e49b13056a145e5de14a75a42e6e5aca68e5): Update CHANGELOG.md -* [472055e](https://github.com/devFelicity/Bot-Frontend/commit/472055e08dad3d5ca62da17bdfe58678f186d74a): Update RecommendedRolls.cs -* [bc39347](https://github.com/devFelicity/Bot-Frontend/commit/bc3934733a5487af1e6baf3fdbaed71ab4e1f6d9): add season of the deep craftables -* [5d6458e](https://github.com/devFelicity/Bot-Frontend/commit/5d6458e989eecda1dd2bcb122d437f55a50360e0): fix case sensitive -# Version: v8.0.0 (21-06-2023) -* [f8ecc00](https://github.com/devFelicity/Bot-Frontend/commit/f8ecc004a6ac6e6b52c308536b8c4a165c139103): Bump Serilog from 2.12.0 to 3.0.0 -* [5da8076](https://github.com/devFelicity/Bot-Frontend/commit/5da807641c65b37c85be7f7f7b4c33e074a723f5): update changelog -* [afd40ae](https://github.com/devFelicity/Bot-Frontend/commit/afd40aed2d32eadc322da548c573097f6554ca18): add color to logging -* [9e32977](https://github.com/devFelicity/Bot-Frontend/commit/9e329776cf26b91055dd5a00d121d50dc100cc3c): String optimisations -* [a634ed7](https://github.com/devFelicity/Bot-Frontend/commit/a634ed7cda149e0291cd26169a377ee8c8f361a8): Bump DotNetBungieAPI from 2.10.0 to 2.11.0 -* [fd75996](https://github.com/devFelicity/Bot-Frontend/commit/fd75996c76208fcb0caebbb18089b6e0542bbca8): Bump Fergun.Interactive from 1.7.1 to 1.7.2 -* [01b340e](https://github.com/devFelicity/Bot-Frontend/commit/01b340e9c254d720fc01e7fdb399f421819f30d2): docs: update .all-contributorsrc [skip ci] -* [38f0e91](https://github.com/devFelicity/Bot-Frontend/commit/38f0e916bee4937ab246505a64528983d8186f70): docs: update README.md [skip ci] -* [ee135b9](https://github.com/devFelicity/Bot-Frontend/commit/ee135b944a5243139a62f98073b64c5465282d28): Fix up readme -* [66a74b0](https://github.com/devFelicity/Bot-Frontend/commit/66a74b09c861367bd2521e55717ef19b5cc56c3f): Bump Sentry.AspNetCore from 3.33.0 to 3.33.1 -* [78c73e1](https://github.com/devFelicity/Bot-Frontend/commit/78c73e16d1527b658da0e82387b81434045aa7de): Update .all-contributorsrc [skip ci] -* [6b7aab8](https://github.com/devFelicity/Bot-Frontend/commit/6b7aab8b39e73603ba32337e7dd2e335c424f0b3): Update README.md [skip ci] -* [a20f1fa](https://github.com/devFelicity/Bot-Frontend/commit/a20f1fa9f0a0ceb90c7a1c22c76d08ab1296c240): Bump Microsoft.EntityFrameworkCore from 7.0.5 to 7.0.7 -* [b384f0d](https://github.com/devFelicity/Bot-Frontend/commit/b384f0d6b14aef362501e22b1889c282ade8bcb8): Bump Sentry.Serilog from 3.33.0 to 3.33.1 -* [773ac97](https://github.com/devFelicity/Bot-Frontend/commit/773ac97b8c41b9d53c1b0bbd72fece4a4e828b62): Fix LW weapons not appearing in crafted -* [eeb1d2b](https://github.com/devFelicity/Bot-Frontend/commit/eeb1d2b0c2c197be0bdcaafe153451931fcc5cc2): update changelog -* [c71e3cb](https://github.com/devFelicity/Bot-Frontend/commit/c71e3cb7776ea0ddd80f54a9fc68b819cc800f3e): fix incorrect urls in /support -* [6aad3c5](https://github.com/devFelicity/Bot-Frontend/commit/6aad3c50d782efe84d588589ca5a04b9a7539ef1): fix dupe in crafted weapons -* [5c5726c](https://github.com/devFelicity/Bot-Frontend/commit/5c5726c8dbf08365e0210fe615cd06096b273a14): Update README.md [skip ci] -* [b11d536](https://github.com/devFelicity/Bot-Frontend/commit/b11d536fee872bb3ef3f0584df698c920b7ff7ab): Update FUNDING.yml [skip ci] -* [f9c57fb](https://github.com/devFelicity/Bot-Frontend/commit/f9c57fb44edbaecc8caf0edd9a3a289ca62ae8cc): push changelog -* [7c141bb](https://github.com/devFelicity/Bot-Frontend/commit/7c141bb90c62a43cdab4b5b3f74d2cafe0a3b57e): cleanup -* [f10c602](https://github.com/devFelicity/Bot-Frontend/commit/f10c602c389e93ef8a8b7abade07413a564edac2): Remove redundant code -* [abb0d34](https://github.com/devFelicity/Bot-Frontend/commit/abb0d34ced01dcfe8f25982e0a1f3224702fea33): Re-add showAll on /recipes -* [cb6c690](https://github.com/devFelicity/Bot-Frontend/commit/cb6c6905d11c0227435a9e42625d3ec08b366725): correct Ada-1 description -* [5a07114](https://github.com/devFelicity/Bot-Frontend/commit/5a07114340c9628518a33fef886f1cc7924cc30b): Added count to rarest emblems -* [04e06b3](https://github.com/devFelicity/Bot-Frontend/commit/04e06b3de6bb6f1e303d75501d4c84b5fabaf4be): missed link change -* [ad4f3bb](https://github.com/devFelicity/Bot-Frontend/commit/ad4f3bb29326cdcaa80c6a4b929762abd798d9d1): bump dependencies -* [099c2f2](https://github.com/devFelicity/Bot-Frontend/commit/099c2f29487dc8b06bbbd697c140dffd99f0ce1c): add self-hosted assets -* [cb0275e](https://github.com/devFelicity/Bot-Frontend/commit/cb0275e5cbe446e2c2f9357cba4b774d054c61e4): add support message -* [7d886f8](https://github.com/devFelicity/Bot-Frontend/commit/7d886f8163de306f98f1584f7f6b1fcb7ef9d797): added GotD loot table -* [ebe4ab3](https://github.com/devFelicity/Bot-Frontend/commit/ebe4ab34f9a5ec17ed9b811dd107a655b5cc0e7b): Fix new version issues -* [a633f18](https://github.com/devFelicity/Bot-Frontend/commit/a633f18aa5f2489439e322d5bb9d2abffe9bf51b): update changelog [skip ci] -* [724494d](https://github.com/devFelicity/Bot-Frontend/commit/724494db4572160030ee939a798f9a4be20cc7f8): fix downgrade issue -* [07c9ec2](https://github.com/devFelicity/Bot-Frontend/commit/07c9ec2067ec325230f0e088bad5cd943aa62633): Bump DotNetBungieAPI from 2.9.0 to 2.10.0 -* [7b41abb](https://github.com/devFelicity/Bot-Frontend/commit/7b41abb0c6c284214c834574b4d83030f07cea35): Update dependabot.yml [skip-ci] -* [ddafacd](https://github.com/devFelicity/Bot-Frontend/commit/ddafacd171b26c0e6e08e359b25d2523b15d17de): docs: update .all-contributorsrc [skip ci] -* [18caba9](https://github.com/devFelicity/Bot-Frontend/commit/18caba9f802b1e5239e134120c2e8d835f00d205): docs: update README.md [skip ci] -* [1405d98](https://github.com/devFelicity/Bot-Frontend/commit/1405d98adaf4704139ebce63ef66819542fd69f3): Update .all-contributorsrc -* [cce0775](https://github.com/devFelicity/Bot-Frontend/commit/cce0775218a1acda390a63132b958a8da1dd7cd4): hopefully fixes cpu loop -* [9a3c95c](https://github.com/devFelicity/Bot-Frontend/commit/9a3c95c2796e84abad2aa6dd9c73660f650bcdc4): forgor changelog -* [0c71112](https://github.com/devFelicity/Bot-Frontend/commit/0c71112609df879e795f0064118fd6384e101602): Update to new auth url (also using as test) -* [079fc25](https://github.com/devFelicity/Bot-Frontend/commit/079fc251e39d528676b7cf974e627c38ff8df4b6): use jq to make a payload -* [f598f0d](https://github.com/devFelicity/Bot-Frontend/commit/f598f0d47c7b9e1fc7e224d99ee2c3c6b9fdd47c): attempt 412323234 at getting commit list to work -* [f2eb7fa](https://github.com/devFelicity/Bot-Frontend/commit/f2eb7fa4f4aa9b3025f45e4edabd299700d239fd): quote marks are weird -* [18676b9](https://github.com/devFelicity/Bot-Frontend/commit/18676b9394d75a9132a667367e3e07020ca77820): fix pr update json -* [8a01efa](https://github.com/devFelicity/Bot-Frontend/commit/8a01efa9e407a02e523013b605bbed913de55cde): Update github action -* [33ed80f](https://github.com/devFelicity/Bot-Frontend/commit/33ed80f313e8159c4c5dda3b22bad0004eb1c0e0): Revert "Update github action" -* [6768cdb](https://github.com/devFelicity/Bot-Frontend/commit/6768cdb3f6980301038ee3e4cbf7eefa9d63a7e1): Update github action -* [900d729](https://github.com/devFelicity/Bot-Frontend/commit/900d729c5b9df70a8caa56da2840f52a37159186): Update changelog -* [12d0910](https://github.com/devFelicity/Bot-Frontend/commit/12d091081a7327e6bda488b401f45a70c5e2813a): add paginator to /recipes -* [6db0329](https://github.com/devFelicity/Bot-Frontend/commit/6db0329e418839fa7b0102ec248d338159eb7bce): cleanup code -* [600795e](https://github.com/devFelicity/Bot-Frontend/commit/600795edf1ef7389d843ddffd8e700c7b8bafc27): add vendor json for debugging -* [9d599cd](https://github.com/devFelicity/Bot-Frontend/commit/9d599cdfa731366634d6789227fd4292d59e4f8d): prevent metrics crash and unrelated errors -* [5f3c037](https://github.com/devFelicity/Bot-Frontend/commit/5f3c037bf8dc892187a1e478188b28f55ea667ea): move embed color to constant -* [49d59ce](https://github.com/devFelicity/Bot-Frontend/commit/49d59ce3e0137fac385071591342c919db8d40e1): start ghosts of the deep loot table -* [e904e44](https://github.com/devFelicity/Bot-Frontend/commit/e904e44817e9251b78287f3aeda71a985b5f01c6): fix rank -* [9468cf0](https://github.com/devFelicity/Bot-Frontend/commit/9468cf0016d68fc6d67c06995f8042d7dcf6dc59): Update loot tables -* [af0dd1b](https://github.com/devFelicity/Bot-Frontend/commit/af0dd1b567c7bcf2c54c7e565be93d16d45f181e): prevents metrics error -* [ac55c60](https://github.com/devFelicity/Bot-Frontend/commit/ac55c608b486a311b29e747b2ba8a2662f202f01): Update dependencies -* [8b66e49](https://github.com/devFelicity/Bot-Frontend/commit/8b66e49b13056a145e5de14a75a42e6e5aca68e5): Update CHANGELOG.md -* [472055e](https://github.com/devFelicity/Bot-Frontend/commit/472055e08dad3d5ca62da17bdfe58678f186d74a): Update RecommendedRolls.cs -* [bc39347](https://github.com/devFelicity/Bot-Frontend/commit/bc3934733a5487af1e6baf3fdbaed71ab4e1f6d9): add season of the deep craftables -* [5d6458e](https://github.com/devFelicity/Bot-Frontend/commit/5d6458e989eecda1dd2bcb122d437f55a50360e0): fix case sensitive -* [395b8fd](https://github.com/devFelicity/Bot-Frontend/commit/395b8fd01ec72fe833e6efdd6e806bce1e9b2979): update changelog -* [43cc474](https://github.com/devFelicity/Bot-Frontend/commit/43cc4747b0166ddfcb174543a74a8ee19d5f168e): add emblem comparison for new manifests -* [9071c1a](https://github.com/devFelicity/Bot-Frontend/commit/9071c1ac65219737e04cc9ea55949d6e8a007008): add status by DissObey -* [f5c9eb2](https://github.com/devFelicity/Bot-Frontend/commit/f5c9eb2c23fa80371680eaeef311a1058d90c93c): add status -* [5427889](https://github.com/devFelicity/Bot-Frontend/commit/54278895667f2ec734469c202ac25bd0a2a12abf): add `/pb raids` -* [8944226](https://github.com/devFelicity/Bot-Frontend/commit/8944226449098354909acfa9d5f8f8b6b482237d): update changelog -* [cda9e1e](https://github.com/devFelicity/Bot-Frontend/commit/cda9e1e18b06c41aa6358b8d818638ca6e41cabd): remove newlines from commit list -* [d1f96b8](https://github.com/devFelicity/Bot-Frontend/commit/d1f96b8a48ac6bb6407536cea3791d6958393c28): update color to fit new logo -* [ae808cc](https://github.com/devFelicity/Bot-Frontend/commit/ae808ccaa1d77e07076aec329f6b9a157770fa41): add metrics -* [273e42c](https://github.com/devFelicity/Bot-Frontend/commit/273e42ca066ec84a151d6f03b32b579668fd4e42): code cleanup -* [39d10a4](https://github.com/devFelicity/Bot-Frontend/commit/39d10a4e51a4308dcd8f39b47febbaa5cdea1938): Update publish.yml +# Version: v8.0.5 (27-06-2023) + +* [a2ea6ee](https://github.com/devFelicity/Bot-Frontend/commit/a2ea6eed2e5e2080f9d44c64c1230243bb596552): Update FUNDING.yml +* [3c84501](https://github.com/devFelicity/Bot-Frontend/commit/3c84501b77228d1b8a4faef8efab1c3979cd8804): ci(docker): update build actions +* [acc95d3](https://github.com/devFelicity/Bot-Frontend/commit/acc95d33cf078c3be25b495cf897f88f33c14e6f): Update publish.yml +* [5c34905](https://github.com/devFelicity/Bot-Frontend/commit/5c34905f6fa3f4e06e8ba27d63fad8e27ac9cac9): Update publish.yml +* [974baa7](https://github.com/devFelicity/Bot-Frontend/commit/974baa7e3765ec7f7942ef9da7ee798fd17f4816): Update publish.yml + + +# Version: v8.0.1 (21-06-2023) +* [eaae19a](https://github.com/devFelicity/Bot-Frontend/commit/eaae19aee0eebeed80cd5bdb625fbe9f2d8db505): docs(changelog): trim unwanted lines [skip ci] +* [b0fa1ad](https://github.com/devFelicity/Bot-Frontend/commit/b0fa1ad2cd85e33942a6f7cb8d04a04ae200ec5a): [Changelog CI] Add Changelog for Version v8.0.0 (21-06-2023) +* [c29bd1d](https://github.com/devFelicity/Bot-Frontend/commit/c29bd1d838fef56c6fcc18a2678467e6ffce5210): ci(changelog): update dependabot settings to be ignored +* [df18cdf](https://github.com/devFelicity/Bot-Frontend/commit/df18cdf2303a023c101defdab70ee34ba90e57e4): ci(changelog): force re-generation with new settings +* [2a3aa14](https://github.com/devFelicity/Bot-Frontend/commit/2a3aa147a41ab95044a16eab529a4a8b26bfdbf1): ci(changelog): trim unwanted lines +* [91426ae](https://github.com/devFelicity/Bot-Frontend/commit/91426ae235c83a447432bfd59400f3e1db6e46b9): [Changelog CI] Add Changelog for Version v8.0.0 (21-06-2023) +* [c127caa](https://github.com/devFelicity/Bot-Frontend/commit/c127caad2974686a2bf8fa1a7fd24eae9fb2f3c1): ci(changelog): remove auto-publisher (will re-add later if I don't forget) +* [e84dd70](https://github.com/devFelicity/Bot-Frontend/commit/e84dd7036ba1ae46788687688d9c21feb0aa2233): ci(changelog): typo in config file name +* [a31b2cd](https://github.com/devFelicity/Bot-Frontend/commit/a31b2cdc65e3288e255c0c69512de92ad85638f2): ci(changelog): delete changelog.md +* [c9d0e10](https://github.com/devFelicity/Bot-Frontend/commit/c9d0e104a7268ba841edbc92fb261d080155fc90): ci(changelog): remove old busted changelog CI +* [fa42235](https://github.com/devFelicity/Bot-Frontend/commit/fa422350f3421f99365d54022330c33aa44324be): feat(rollfinder): add support for new layout +* [4a94b22](https://github.com/devFelicity/Bot-Frontend/commit/4a94b228fcdf4e6899dee68afb680a0f4808c1fe): style(main): auto-cleanup +* [85c11cb](https://github.com/devFelicity/Bot-Frontend/commit/85c11cb6a004b33372399f38744939e1099d2bc2): Merge remote-tracking branch 'origin/develop' into develop +* [6014cc0](https://github.com/devFelicity/Bot-Frontend/commit/6014cc025d003694311c403d1f002d33ac142844): feat(debug): add WSL support and commitizen +* [f8ecc00](https://github.com/devFelicity/Bot-Frontend/commit/f8ecc004a6ac6e6b52c308536b8c4a165c139103): Bump Serilog from 2.12.0 to 3.0.0 +* [5da8076](https://github.com/devFelicity/Bot-Frontend/commit/5da807641c65b37c85be7f7f7b4c33e074a723f5): update changelog +* [afd40ae](https://github.com/devFelicity/Bot-Frontend/commit/afd40aed2d32eadc322da548c573097f6554ca18): add color to logging +* [9e32977](https://github.com/devFelicity/Bot-Frontend/commit/9e329776cf26b91055dd5a00d121d50dc100cc3c): String optimisations +* [a634ed7](https://github.com/devFelicity/Bot-Frontend/commit/a634ed7cda149e0291cd26169a377ee8c8f361a8): Bump DotNetBungieAPI from 2.10.0 to 2.11.0 +* [fd75996](https://github.com/devFelicity/Bot-Frontend/commit/fd75996c76208fcb0caebbb18089b6e0542bbca8): Bump Fergun.Interactive from 1.7.1 to 1.7.2 +* [01b340e](https://github.com/devFelicity/Bot-Frontend/commit/01b340e9c254d720fc01e7fdb399f421819f30d2): docs: update .all-contributorsrc [skip ci] +* [38f0e91](https://github.com/devFelicity/Bot-Frontend/commit/38f0e916bee4937ab246505a64528983d8186f70): docs: update README.md [skip ci] +* [ee135b9](https://github.com/devFelicity/Bot-Frontend/commit/ee135b944a5243139a62f98073b64c5465282d28): Fix up readme +* [66a74b0](https://github.com/devFelicity/Bot-Frontend/commit/66a74b09c861367bd2521e55717ef19b5cc56c3f): Bump Sentry.AspNetCore from 3.33.0 to 3.33.1 +* [78c73e1](https://github.com/devFelicity/Bot-Frontend/commit/78c73e16d1527b658da0e82387b81434045aa7de): Update .all-contributorsrc [skip ci] +* [6b7aab8](https://github.com/devFelicity/Bot-Frontend/commit/6b7aab8b39e73603ba32337e7dd2e335c424f0b3): Update README.md [skip ci] +* [a20f1fa](https://github.com/devFelicity/Bot-Frontend/commit/a20f1fa9f0a0ceb90c7a1c22c76d08ab1296c240): Bump Microsoft.EntityFrameworkCore from 7.0.5 to 7.0.7 +* [b384f0d](https://github.com/devFelicity/Bot-Frontend/commit/b384f0d6b14aef362501e22b1889c282ade8bcb8): Bump Sentry.Serilog from 3.33.0 to 3.33.1 +* [773ac97](https://github.com/devFelicity/Bot-Frontend/commit/773ac97b8c41b9d53c1b0bbd72fece4a4e828b62): Fix LW weapons not appearing in crafted +* [eeb1d2b](https://github.com/devFelicity/Bot-Frontend/commit/eeb1d2b0c2c197be0bdcaafe153451931fcc5cc2): update changelog +* [c71e3cb](https://github.com/devFelicity/Bot-Frontend/commit/c71e3cb7776ea0ddd80f54a9fc68b819cc800f3e): fix incorrect urls in /support +* [6aad3c5](https://github.com/devFelicity/Bot-Frontend/commit/6aad3c50d782efe84d588589ca5a04b9a7539ef1): fix dupe in crafted weapons +* [5c5726c](https://github.com/devFelicity/Bot-Frontend/commit/5c5726c8dbf08365e0210fe615cd06096b273a14): Update README.md [skip ci] +* [b11d536](https://github.com/devFelicity/Bot-Frontend/commit/b11d536fee872bb3ef3f0584df698c920b7ff7ab): Update FUNDING.yml [skip ci] +* [f9c57fb](https://github.com/devFelicity/Bot-Frontend/commit/f9c57fb44edbaecc8caf0edd9a3a289ca62ae8cc): push changelog +* [7c141bb](https://github.com/devFelicity/Bot-Frontend/commit/7c141bb90c62a43cdab4b5b3f74d2cafe0a3b57e): cleanup +* [f10c602](https://github.com/devFelicity/Bot-Frontend/commit/f10c602c389e93ef8a8b7abade07413a564edac2): Remove redundant code +* [abb0d34](https://github.com/devFelicity/Bot-Frontend/commit/abb0d34ced01dcfe8f25982e0a1f3224702fea33): Re-add showAll on /recipes +* [cb6c690](https://github.com/devFelicity/Bot-Frontend/commit/cb6c6905d11c0227435a9e42625d3ec08b366725): correct Ada-1 description +* [5a07114](https://github.com/devFelicity/Bot-Frontend/commit/5a07114340c9628518a33fef886f1cc7924cc30b): Added count to rarest emblems +* [04e06b3](https://github.com/devFelicity/Bot-Frontend/commit/04e06b3de6bb6f1e303d75501d4c84b5fabaf4be): missed link change +* [ad4f3bb](https://github.com/devFelicity/Bot-Frontend/commit/ad4f3bb29326cdcaa80c6a4b929762abd798d9d1): bump dependencies +* [099c2f2](https://github.com/devFelicity/Bot-Frontend/commit/099c2f29487dc8b06bbbd697c140dffd99f0ce1c): add self-hosted assets +* [cb0275e](https://github.com/devFelicity/Bot-Frontend/commit/cb0275e5cbe446e2c2f9357cba4b774d054c61e4): add support message +* [7d886f8](https://github.com/devFelicity/Bot-Frontend/commit/7d886f8163de306f98f1584f7f6b1fcb7ef9d797): added GotD loot table +* [ebe4ab3](https://github.com/devFelicity/Bot-Frontend/commit/ebe4ab34f9a5ec17ed9b811dd107a655b5cc0e7b): Fix new version issues +* [a633f18](https://github.com/devFelicity/Bot-Frontend/commit/a633f18aa5f2489439e322d5bb9d2abffe9bf51b): update changelog [skip ci] +* [724494d](https://github.com/devFelicity/Bot-Frontend/commit/724494db4572160030ee939a798f9a4be20cc7f8): fix downgrade issue +* [07c9ec2](https://github.com/devFelicity/Bot-Frontend/commit/07c9ec2067ec325230f0e088bad5cd943aa62633): Bump DotNetBungieAPI from 2.9.0 to 2.10.0 +* [7b41abb](https://github.com/devFelicity/Bot-Frontend/commit/7b41abb0c6c284214c834574b4d83030f07cea35): Update dependabot.yml [skip-ci] +* [ddafacd](https://github.com/devFelicity/Bot-Frontend/commit/ddafacd171b26c0e6e08e359b25d2523b15d17de): docs: update .all-contributorsrc [skip ci] +* [18caba9](https://github.com/devFelicity/Bot-Frontend/commit/18caba9f802b1e5239e134120c2e8d835f00d205): docs: update README.md [skip ci] +* [1405d98](https://github.com/devFelicity/Bot-Frontend/commit/1405d98adaf4704139ebce63ef66819542fd69f3): Update .all-contributorsrc +* [cce0775](https://github.com/devFelicity/Bot-Frontend/commit/cce0775218a1acda390a63132b958a8da1dd7cd4): hopefully fixes cpu loop +* [9a3c95c](https://github.com/devFelicity/Bot-Frontend/commit/9a3c95c2796e84abad2aa6dd9c73660f650bcdc4): forgor changelog +* [0c71112](https://github.com/devFelicity/Bot-Frontend/commit/0c71112609df879e795f0064118fd6384e101602): Update to new auth url (also using as test) +* [079fc25](https://github.com/devFelicity/Bot-Frontend/commit/079fc251e39d528676b7cf974e627c38ff8df4b6): use jq to make a payload +* [f598f0d](https://github.com/devFelicity/Bot-Frontend/commit/f598f0d47c7b9e1fc7e224d99ee2c3c6b9fdd47c): attempt 412323234 at getting commit list to work +* [f2eb7fa](https://github.com/devFelicity/Bot-Frontend/commit/f2eb7fa4f4aa9b3025f45e4edabd299700d239fd): quote marks are weird +* [18676b9](https://github.com/devFelicity/Bot-Frontend/commit/18676b9394d75a9132a667367e3e07020ca77820): fix pr update json +* [8a01efa](https://github.com/devFelicity/Bot-Frontend/commit/8a01efa9e407a02e523013b605bbed913de55cde): Update github action +* [33ed80f](https://github.com/devFelicity/Bot-Frontend/commit/33ed80f313e8159c4c5dda3b22bad0004eb1c0e0): Revert "Update github action" +* [6768cdb](https://github.com/devFelicity/Bot-Frontend/commit/6768cdb3f6980301038ee3e4cbf7eefa9d63a7e1): Update github action +* [900d729](https://github.com/devFelicity/Bot-Frontend/commit/900d729c5b9df70a8caa56da2840f52a37159186): Update changelog +* [12d0910](https://github.com/devFelicity/Bot-Frontend/commit/12d091081a7327e6bda488b401f45a70c5e2813a): add paginator to /recipes +* [6db0329](https://github.com/devFelicity/Bot-Frontend/commit/6db0329e418839fa7b0102ec248d338159eb7bce): cleanup code +* [600795e](https://github.com/devFelicity/Bot-Frontend/commit/600795edf1ef7389d843ddffd8e700c7b8bafc27): add vendor json for debugging +* [9d599cd](https://github.com/devFelicity/Bot-Frontend/commit/9d599cdfa731366634d6789227fd4292d59e4f8d): prevent metrics crash and unrelated errors +* [5f3c037](https://github.com/devFelicity/Bot-Frontend/commit/5f3c037bf8dc892187a1e478188b28f55ea667ea): move embed color to constant +* [49d59ce](https://github.com/devFelicity/Bot-Frontend/commit/49d59ce3e0137fac385071591342c919db8d40e1): start ghosts of the deep loot table +* [e904e44](https://github.com/devFelicity/Bot-Frontend/commit/e904e44817e9251b78287f3aeda71a985b5f01c6): fix rank +* [9468cf0](https://github.com/devFelicity/Bot-Frontend/commit/9468cf0016d68fc6d67c06995f8042d7dcf6dc59): Update loot tables +* [af0dd1b](https://github.com/devFelicity/Bot-Frontend/commit/af0dd1b567c7bcf2c54c7e565be93d16d45f181e): prevents metrics error +* [ac55c60](https://github.com/devFelicity/Bot-Frontend/commit/ac55c608b486a311b29e747b2ba8a2662f202f01): Update dependencies +* [8b66e49](https://github.com/devFelicity/Bot-Frontend/commit/8b66e49b13056a145e5de14a75a42e6e5aca68e5): Update CHANGELOG.md +* [472055e](https://github.com/devFelicity/Bot-Frontend/commit/472055e08dad3d5ca62da17bdfe58678f186d74a): Update RecommendedRolls.cs +* [bc39347](https://github.com/devFelicity/Bot-Frontend/commit/bc3934733a5487af1e6baf3fdbaed71ab4e1f6d9): add season of the deep craftables +* [5d6458e](https://github.com/devFelicity/Bot-Frontend/commit/5d6458e989eecda1dd2bcb122d437f55a50360e0): fix case sensitive +# Version: v8.0.0 (21-06-2023) +* [f8ecc00](https://github.com/devFelicity/Bot-Frontend/commit/f8ecc004a6ac6e6b52c308536b8c4a165c139103): Bump Serilog from 2.12.0 to 3.0.0 +* [5da8076](https://github.com/devFelicity/Bot-Frontend/commit/5da807641c65b37c85be7f7f7b4c33e074a723f5): update changelog +* [afd40ae](https://github.com/devFelicity/Bot-Frontend/commit/afd40aed2d32eadc322da548c573097f6554ca18): add color to logging +* [9e32977](https://github.com/devFelicity/Bot-Frontend/commit/9e329776cf26b91055dd5a00d121d50dc100cc3c): String optimisations +* [a634ed7](https://github.com/devFelicity/Bot-Frontend/commit/a634ed7cda149e0291cd26169a377ee8c8f361a8): Bump DotNetBungieAPI from 2.10.0 to 2.11.0 +* [fd75996](https://github.com/devFelicity/Bot-Frontend/commit/fd75996c76208fcb0caebbb18089b6e0542bbca8): Bump Fergun.Interactive from 1.7.1 to 1.7.2 +* [01b340e](https://github.com/devFelicity/Bot-Frontend/commit/01b340e9c254d720fc01e7fdb399f421819f30d2): docs: update .all-contributorsrc [skip ci] +* [38f0e91](https://github.com/devFelicity/Bot-Frontend/commit/38f0e916bee4937ab246505a64528983d8186f70): docs: update README.md [skip ci] +* [ee135b9](https://github.com/devFelicity/Bot-Frontend/commit/ee135b944a5243139a62f98073b64c5465282d28): Fix up readme +* [66a74b0](https://github.com/devFelicity/Bot-Frontend/commit/66a74b09c861367bd2521e55717ef19b5cc56c3f): Bump Sentry.AspNetCore from 3.33.0 to 3.33.1 +* [78c73e1](https://github.com/devFelicity/Bot-Frontend/commit/78c73e16d1527b658da0e82387b81434045aa7de): Update .all-contributorsrc [skip ci] +* [6b7aab8](https://github.com/devFelicity/Bot-Frontend/commit/6b7aab8b39e73603ba32337e7dd2e335c424f0b3): Update README.md [skip ci] +* [a20f1fa](https://github.com/devFelicity/Bot-Frontend/commit/a20f1fa9f0a0ceb90c7a1c22c76d08ab1296c240): Bump Microsoft.EntityFrameworkCore from 7.0.5 to 7.0.7 +* [b384f0d](https://github.com/devFelicity/Bot-Frontend/commit/b384f0d6b14aef362501e22b1889c282ade8bcb8): Bump Sentry.Serilog from 3.33.0 to 3.33.1 +* [773ac97](https://github.com/devFelicity/Bot-Frontend/commit/773ac97b8c41b9d53c1b0bbd72fece4a4e828b62): Fix LW weapons not appearing in crafted +* [eeb1d2b](https://github.com/devFelicity/Bot-Frontend/commit/eeb1d2b0c2c197be0bdcaafe153451931fcc5cc2): update changelog +* [c71e3cb](https://github.com/devFelicity/Bot-Frontend/commit/c71e3cb7776ea0ddd80f54a9fc68b819cc800f3e): fix incorrect urls in /support +* [6aad3c5](https://github.com/devFelicity/Bot-Frontend/commit/6aad3c50d782efe84d588589ca5a04b9a7539ef1): fix dupe in crafted weapons +* [5c5726c](https://github.com/devFelicity/Bot-Frontend/commit/5c5726c8dbf08365e0210fe615cd06096b273a14): Update README.md [skip ci] +* [b11d536](https://github.com/devFelicity/Bot-Frontend/commit/b11d536fee872bb3ef3f0584df698c920b7ff7ab): Update FUNDING.yml [skip ci] +* [f9c57fb](https://github.com/devFelicity/Bot-Frontend/commit/f9c57fb44edbaecc8caf0edd9a3a289ca62ae8cc): push changelog +* [7c141bb](https://github.com/devFelicity/Bot-Frontend/commit/7c141bb90c62a43cdab4b5b3f74d2cafe0a3b57e): cleanup +* [f10c602](https://github.com/devFelicity/Bot-Frontend/commit/f10c602c389e93ef8a8b7abade07413a564edac2): Remove redundant code +* [abb0d34](https://github.com/devFelicity/Bot-Frontend/commit/abb0d34ced01dcfe8f25982e0a1f3224702fea33): Re-add showAll on /recipes +* [cb6c690](https://github.com/devFelicity/Bot-Frontend/commit/cb6c6905d11c0227435a9e42625d3ec08b366725): correct Ada-1 description +* [5a07114](https://github.com/devFelicity/Bot-Frontend/commit/5a07114340c9628518a33fef886f1cc7924cc30b): Added count to rarest emblems +* [04e06b3](https://github.com/devFelicity/Bot-Frontend/commit/04e06b3de6bb6f1e303d75501d4c84b5fabaf4be): missed link change +* [ad4f3bb](https://github.com/devFelicity/Bot-Frontend/commit/ad4f3bb29326cdcaa80c6a4b929762abd798d9d1): bump dependencies +* [099c2f2](https://github.com/devFelicity/Bot-Frontend/commit/099c2f29487dc8b06bbbd697c140dffd99f0ce1c): add self-hosted assets +* [cb0275e](https://github.com/devFelicity/Bot-Frontend/commit/cb0275e5cbe446e2c2f9357cba4b774d054c61e4): add support message +* [7d886f8](https://github.com/devFelicity/Bot-Frontend/commit/7d886f8163de306f98f1584f7f6b1fcb7ef9d797): added GotD loot table +* [ebe4ab3](https://github.com/devFelicity/Bot-Frontend/commit/ebe4ab34f9a5ec17ed9b811dd107a655b5cc0e7b): Fix new version issues +* [a633f18](https://github.com/devFelicity/Bot-Frontend/commit/a633f18aa5f2489439e322d5bb9d2abffe9bf51b): update changelog [skip ci] +* [724494d](https://github.com/devFelicity/Bot-Frontend/commit/724494db4572160030ee939a798f9a4be20cc7f8): fix downgrade issue +* [07c9ec2](https://github.com/devFelicity/Bot-Frontend/commit/07c9ec2067ec325230f0e088bad5cd943aa62633): Bump DotNetBungieAPI from 2.9.0 to 2.10.0 +* [7b41abb](https://github.com/devFelicity/Bot-Frontend/commit/7b41abb0c6c284214c834574b4d83030f07cea35): Update dependabot.yml [skip-ci] +* [ddafacd](https://github.com/devFelicity/Bot-Frontend/commit/ddafacd171b26c0e6e08e359b25d2523b15d17de): docs: update .all-contributorsrc [skip ci] +* [18caba9](https://github.com/devFelicity/Bot-Frontend/commit/18caba9f802b1e5239e134120c2e8d835f00d205): docs: update README.md [skip ci] +* [1405d98](https://github.com/devFelicity/Bot-Frontend/commit/1405d98adaf4704139ebce63ef66819542fd69f3): Update .all-contributorsrc +* [cce0775](https://github.com/devFelicity/Bot-Frontend/commit/cce0775218a1acda390a63132b958a8da1dd7cd4): hopefully fixes cpu loop +* [9a3c95c](https://github.com/devFelicity/Bot-Frontend/commit/9a3c95c2796e84abad2aa6dd9c73660f650bcdc4): forgor changelog +* [0c71112](https://github.com/devFelicity/Bot-Frontend/commit/0c71112609df879e795f0064118fd6384e101602): Update to new auth url (also using as test) +* [079fc25](https://github.com/devFelicity/Bot-Frontend/commit/079fc251e39d528676b7cf974e627c38ff8df4b6): use jq to make a payload +* [f598f0d](https://github.com/devFelicity/Bot-Frontend/commit/f598f0d47c7b9e1fc7e224d99ee2c3c6b9fdd47c): attempt 412323234 at getting commit list to work +* [f2eb7fa](https://github.com/devFelicity/Bot-Frontend/commit/f2eb7fa4f4aa9b3025f45e4edabd299700d239fd): quote marks are weird +* [18676b9](https://github.com/devFelicity/Bot-Frontend/commit/18676b9394d75a9132a667367e3e07020ca77820): fix pr update json +* [8a01efa](https://github.com/devFelicity/Bot-Frontend/commit/8a01efa9e407a02e523013b605bbed913de55cde): Update github action +* [33ed80f](https://github.com/devFelicity/Bot-Frontend/commit/33ed80f313e8159c4c5dda3b22bad0004eb1c0e0): Revert "Update github action" +* [6768cdb](https://github.com/devFelicity/Bot-Frontend/commit/6768cdb3f6980301038ee3e4cbf7eefa9d63a7e1): Update github action +* [900d729](https://github.com/devFelicity/Bot-Frontend/commit/900d729c5b9df70a8caa56da2840f52a37159186): Update changelog +* [12d0910](https://github.com/devFelicity/Bot-Frontend/commit/12d091081a7327e6bda488b401f45a70c5e2813a): add paginator to /recipes +* [6db0329](https://github.com/devFelicity/Bot-Frontend/commit/6db0329e418839fa7b0102ec248d338159eb7bce): cleanup code +* [600795e](https://github.com/devFelicity/Bot-Frontend/commit/600795edf1ef7389d843ddffd8e700c7b8bafc27): add vendor json for debugging +* [9d599cd](https://github.com/devFelicity/Bot-Frontend/commit/9d599cdfa731366634d6789227fd4292d59e4f8d): prevent metrics crash and unrelated errors +* [5f3c037](https://github.com/devFelicity/Bot-Frontend/commit/5f3c037bf8dc892187a1e478188b28f55ea667ea): move embed color to constant +* [49d59ce](https://github.com/devFelicity/Bot-Frontend/commit/49d59ce3e0137fac385071591342c919db8d40e1): start ghosts of the deep loot table +* [e904e44](https://github.com/devFelicity/Bot-Frontend/commit/e904e44817e9251b78287f3aeda71a985b5f01c6): fix rank +* [9468cf0](https://github.com/devFelicity/Bot-Frontend/commit/9468cf0016d68fc6d67c06995f8042d7dcf6dc59): Update loot tables +* [af0dd1b](https://github.com/devFelicity/Bot-Frontend/commit/af0dd1b567c7bcf2c54c7e565be93d16d45f181e): prevents metrics error +* [ac55c60](https://github.com/devFelicity/Bot-Frontend/commit/ac55c608b486a311b29e747b2ba8a2662f202f01): Update dependencies +* [8b66e49](https://github.com/devFelicity/Bot-Frontend/commit/8b66e49b13056a145e5de14a75a42e6e5aca68e5): Update CHANGELOG.md +* [472055e](https://github.com/devFelicity/Bot-Frontend/commit/472055e08dad3d5ca62da17bdfe58678f186d74a): Update RecommendedRolls.cs +* [bc39347](https://github.com/devFelicity/Bot-Frontend/commit/bc3934733a5487af1e6baf3fdbaed71ab4e1f6d9): add season of the deep craftables +* [5d6458e](https://github.com/devFelicity/Bot-Frontend/commit/5d6458e989eecda1dd2bcb122d437f55a50360e0): fix case sensitive +* [395b8fd](https://github.com/devFelicity/Bot-Frontend/commit/395b8fd01ec72fe833e6efdd6e806bce1e9b2979): update changelog +* [43cc474](https://github.com/devFelicity/Bot-Frontend/commit/43cc4747b0166ddfcb174543a74a8ee19d5f168e): add emblem comparison for new manifests +* [9071c1a](https://github.com/devFelicity/Bot-Frontend/commit/9071c1ac65219737e04cc9ea55949d6e8a007008): add status by DissObey +* [f5c9eb2](https://github.com/devFelicity/Bot-Frontend/commit/f5c9eb2c23fa80371680eaeef311a1058d90c93c): add status +* [5427889](https://github.com/devFelicity/Bot-Frontend/commit/54278895667f2ec734469c202ac25bd0a2a12abf): add `/pb raids` +* [8944226](https://github.com/devFelicity/Bot-Frontend/commit/8944226449098354909acfa9d5f8f8b6b482237d): update changelog +* [cda9e1e](https://github.com/devFelicity/Bot-Frontend/commit/cda9e1e18b06c41aa6358b8d818638ca6e41cabd): remove newlines from commit list +* [d1f96b8](https://github.com/devFelicity/Bot-Frontend/commit/d1f96b8a48ac6bb6407536cea3791d6958393c28): update color to fit new logo +* [ae808cc](https://github.com/devFelicity/Bot-Frontend/commit/ae808ccaa1d77e07076aec329f6b9a157770fa41): add metrics +* [273e42c](https://github.com/devFelicity/Bot-Frontend/commit/273e42ca066ec84a151d6f03b32b579668fd4e42): code cleanup +* [39d10a4](https://github.com/devFelicity/Bot-Frontend/commit/39d10a4e51a4308dcd8f39b47febbaa5cdea1938): Update publish.yml diff --git a/Dockerfile b/Dockerfile index 770678d..cc159ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,22 @@ -#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. - -FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base -WORKDIR /app -EXPOSE 80 -EXPOSE 443 - -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build -WORKDIR /src -COPY ["Felicity/Felicity.csproj", "Felicity/"] -RUN dotnet restore "Felicity/Felicity.csproj" -COPY . . -WORKDIR "/src/Felicity" -RUN dotnet build "Felicity.csproj" -c Release -o /app/build - -FROM build AS publish -RUN dotnet publish "Felicity.csproj" -c Release -o /app/publish - -FROM base AS final -WORKDIR /app -COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "Felicity.dll"] +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["Felicity/Felicity.csproj", "Felicity/"] +RUN dotnet restore "Felicity/Felicity.csproj" +COPY . . +WORKDIR "/src/Felicity" +RUN dotnet build "Felicity.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Felicity.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Felicity.dll"] diff --git a/Felicity.sln b/Felicity.sln index d852d62..60d5e90 100644 --- a/Felicity.sln +++ b/Felicity.sln @@ -1,35 +1,35 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.2.32616.157 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Felicity", "Felicity\Felicity.csproj", "{D150851D-8F3F-40CD-BB34-904ED3CD0935}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E25BFF59-2E80-4217-821B-18F330B54B4B}" - ProjectSection(SolutionItems) = preProject - CHANGELOG.md = CHANGELOG.md - CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md - CONTRIBUTING.md = CONTRIBUTING.md - Dockerfile = Dockerfile - LICENSE.md = LICENSE.md - README.md = README.md - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {44EE387E-EF7E-45D8-9658-3B88CCDBF797} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Felicity", "Felicity\Felicity.csproj", "{D150851D-8F3F-40CD-BB34-904ED3CD0935}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E25BFF59-2E80-4217-821B-18F330B54B4B}" + ProjectSection(SolutionItems) = preProject + CHANGELOG.md = CHANGELOG.md + CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md + CONTRIBUTING.md = CONTRIBUTING.md + Dockerfile = Dockerfile + LICENSE.md = LICENSE.md + README.md = README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D150851D-8F3F-40CD-BB34-904ED3CD0935}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {44EE387E-EF7E-45D8-9658-3B88CCDBF797} + EndGlobalSection +EndGlobal diff --git a/Felicity/.config/dotnet-tools.json b/Felicity/.config/dotnet-tools.json index 558293e..fc227a2 100644 --- a/Felicity/.config/dotnet-tools.json +++ b/Felicity/.config/dotnet-tools.json @@ -1,12 +1,12 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "dotnet-ef": { - "version": "7.0.10", - "commands": [ - "dotnet-ef" - ] - } - } +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "7.0.10", + "commands": [ + "dotnet-ef" + ] + } + } } \ No newline at end of file diff --git a/Felicity/DiscordCommands/Interactions/CheckpointCommands.cs b/Felicity/DiscordCommands/Interactions/CheckpointCommands.cs index 9e41291..0dc8c9c 100644 --- a/Felicity/DiscordCommands/Interactions/CheckpointCommands.cs +++ b/Felicity/DiscordCommands/Interactions/CheckpointCommands.cs @@ -1,94 +1,94 @@ -using System.Text; -using Discord; -using Discord.Interactions; -using Felicity.Models; -using Felicity.Util; - -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global - -namespace Felicity.DiscordCommands.Interactions; - -public class CheckpointCommands : InteractionModuleBase -{ - [SlashCommand("checkpoint-list", "List all available checkpoints and their status.")] - public async Task CheckpointList() - { - await DeferAsync(); - - var checkpointList = await CheckpointParser.FetchAsync(); - - var embed = Embeds.MakeBuilder(); - - embed.Author = new EmbedAuthorBuilder - { - Name = "D2Checkpoint.com", - IconUrl = "https://cdn.tryfelicity.one/images/d2cp.png", - Url = "https://d2checkpoint.com" - }; - - embed.ThumbnailUrl = - "https://www.bungie.net/common/destiny2_content/icons/8b1bfd1c1ce1cab51d23c78235a6e067.png"; - - embed.Title = "All available checkpoints:"; - - var sb = new StringBuilder(); - - if (checkpointList?.Official != null) - foreach (var officialCp in checkpointList.Official) - sb.Append( - $"{Format.Bold(officialCp.Activity)} - {officialCp.Encounter} [{officialCp.Players}/{officialCp.MaxPlayers}]" + - $"\n{Format.Code($"/join {officialCp.Name}")}\n\n"); - else - sb.Append("Checkpoint list unavailable."); - - embed.Description = sb.ToString(); - - await FollowupAsync(embed: embed.Build()); - } - - [SlashCommand("checkpoint", "Find a checkpoint and join it.")] - public async Task Checkpoint( - [Autocomplete(typeof(CheckpointAutocomplete))] [Summary("name", "Activity/Encounter to search for:")] - int displayOrder) - { - await DeferAsync(); - - var checkpointList = await CheckpointParser.FetchAsync(); - - // ReSharper disable once MergeSequentialChecks - var failed = checkpointList == null && checkpointList?.Official != null; - - var currentCheckpoint = checkpointList?.Official?.FirstOrDefault(x => x.DisplayOrder == displayOrder); - if (currentCheckpoint == null) failed = true; - - if (failed) - { - var errEmbed = Embeds.MakeErrorEmbed(); - errEmbed.Description = "Failed to fetch checkpoint list."; - - await FollowupAsync(embed: errEmbed.Build()); - return; - } - - var embed = Embeds.MakeBuilder(); - - embed.Author = new EmbedAuthorBuilder - { - Name = "D2Checkpoint.com", - IconUrl = "https://cdn.tryfelicity.one/images/d2cp.png", - Url = "https://d2checkpoint.com" - }; - -#pragma warning disable CS8602 - embed.ThumbnailUrl = currentCheckpoint.IconUrl; - embed.ImageUrl = currentCheckpoint.ImgUrl; - embed.Title = $"{currentCheckpoint.Activity} - {currentCheckpoint.Encounter}"; - embed.Description = Format.Code($"/join {currentCheckpoint.Name}"); - embed.AddField("Players", $"{currentCheckpoint.Players}/{currentCheckpoint.MaxPlayers}", true); - embed.AddField("Difficulty", currentCheckpoint.DifficultyTier.ToString(), true); -#pragma warning restore CS8602 - - await FollowupAsync(embed: embed.Build()); - } +using System.Text; +using Discord; +using Discord.Interactions; +using Felicity.Models; +using Felicity.Util; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace Felicity.DiscordCommands.Interactions; + +public class CheckpointCommands : InteractionModuleBase +{ + [SlashCommand("checkpoint-list", "List all available checkpoints and their status.")] + public async Task CheckpointList() + { + await DeferAsync(); + + var checkpointList = await CheckpointParser.FetchAsync(); + + var embed = Embeds.MakeBuilder(); + + embed.Author = new EmbedAuthorBuilder + { + Name = "D2Checkpoint.com", + IconUrl = "https://cdn.tryfelicity.one/images/d2cp.png", + Url = "https://d2checkpoint.com" + }; + + embed.ThumbnailUrl = + "https://www.bungie.net/common/destiny2_content/icons/8b1bfd1c1ce1cab51d23c78235a6e067.png"; + + embed.Title = "All available checkpoints:"; + + var sb = new StringBuilder(); + + if (checkpointList?.Official != null) + foreach (var officialCp in checkpointList.Official) + sb.Append( + $"{Format.Bold(officialCp.Activity)} - {officialCp.Encounter} [{officialCp.Players}/{officialCp.MaxPlayers}]" + + $"\n{Format.Code($"/join {officialCp.Name}")}\n\n"); + else + sb.Append("Checkpoint list unavailable."); + + embed.Description = sb.ToString(); + + await FollowupAsync(embed: embed.Build()); + } + + [SlashCommand("checkpoint", "Find a checkpoint and join it.")] + public async Task Checkpoint( + [Autocomplete(typeof(CheckpointAutocomplete))] [Summary("name", "Activity/Encounter to search for:")] + int displayOrder) + { + await DeferAsync(); + + var checkpointList = await CheckpointParser.FetchAsync(); + + // ReSharper disable once MergeSequentialChecks + var failed = checkpointList == null && checkpointList?.Official != null; + + var currentCheckpoint = checkpointList?.Official?.FirstOrDefault(x => x.DisplayOrder == displayOrder); + if (currentCheckpoint == null) failed = true; + + if (failed) + { + var errEmbed = Embeds.MakeErrorEmbed(); + errEmbed.Description = "Failed to fetch checkpoint list."; + + await FollowupAsync(embed: errEmbed.Build()); + return; + } + + var embed = Embeds.MakeBuilder(); + + embed.Author = new EmbedAuthorBuilder + { + Name = "D2Checkpoint.com", + IconUrl = "https://cdn.tryfelicity.one/images/d2cp.png", + Url = "https://d2checkpoint.com" + }; + +#pragma warning disable CS8602 + embed.ThumbnailUrl = currentCheckpoint.IconUrl; + embed.ImageUrl = currentCheckpoint.ImgUrl; + embed.Title = $"{currentCheckpoint.Activity} - {currentCheckpoint.Encounter}"; + embed.Description = Format.Code($"/join {currentCheckpoint.Name}"); + embed.AddField("Players", $"{currentCheckpoint.Players}/{currentCheckpoint.MaxPlayers}", true); + embed.AddField("Difficulty", currentCheckpoint.DifficultyTier.ToString(), true); +#pragma warning restore CS8602 + + await FollowupAsync(embed: embed.Build()); + } } \ No newline at end of file diff --git a/Felicity/DiscordCommands/Interactions/EmblemCommands.cs b/Felicity/DiscordCommands/Interactions/EmblemCommands.cs index 7b88e92..0af6982 100644 --- a/Felicity/DiscordCommands/Interactions/EmblemCommands.cs +++ b/Felicity/DiscordCommands/Interactions/EmblemCommands.cs @@ -1,386 +1,386 @@ -using System.Text; -using System.Text.Json; -using Discord; -using Discord.Interactions; -using DotNetBungieAPI.Extensions; -using DotNetBungieAPI.Models; -using DotNetBungieAPI.Models.Destiny; -using DotNetBungieAPI.Models.Destiny.Definitions.Collectibles; -using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; -using DotNetBungieAPI.Models.Destiny.Responses; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Models; -using Felicity.Options; -using Felicity.Util; -using Felicity.Util.Enums; -using Microsoft.Extensions.Options; - -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global - -namespace Felicity.DiscordCommands.Interactions; - -[Group("emblem", "Various lookup commands for Destiny 2.")] -public class EmblemCommands : InteractionModuleBase -{ - private readonly IBungieClient _bungieClient; - private readonly UserDb _userDb; - private readonly IOptions _botOptions; - - public EmblemCommands(IBungieClient bungieClient, UserDb userDb, IOptions botOptions) - { - _bungieClient = bungieClient; - _userDb = userDb; - _botOptions = botOptions; - } - - [SlashCommand("shares", "Look up account shared emblems of a player.")] - public async Task EmblemShares( - [Summary("bungie-name", - "Bungie name of the requested user (name#1234).")] - string bungieTag = "") - { - await DeferAsync(); - - if (!await BungieApiUtils.CheckApi(_bungieClient)) - throw new Exception("Bungie API is down or unresponsive."); - - if (!string.IsNullOrEmpty(bungieTag) && !bungieTag.Contains('#')) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = - $"`{bungieTag}` is not a correct format for a Bungie name.\nTry again with the `#` format."; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var requestedProfile = - await ProfileHelper.GetRequestedProfile(bungieTag, Context.User.Id, _userDb, _bungieClient); - - if (!string.IsNullOrEmpty(requestedProfile.Error)) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = requestedProfile.Error; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var profile = await _bungieClient.ApiAccess.Destiny2.GetProfile(requestedProfile.MembershipType, - requestedProfile.MembershipId, new[] - { - DestinyComponentType.Characters, DestinyComponentType.Profiles, DestinyComponentType.Collectibles - }); - - // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract - // Note to self, bungie privacy sucks ass and always reports privacy as private. - if (profile.Response.ProfileCollectibles.Data == null) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = $"`{bungieTag}` has their collections set to private, unable to parse emblems."; - - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var emblemCount = 0; - var emblemList = new List(); - - var manifestInventoryItemIDs = profile.Response.Characters.Data - .Select(destinyCharacterComponent => destinyCharacterComponent.Value.Emblem.Hash).ToList(); - var manifestCollectibleIDs = - profile.Response.ProfileCollectibles.Data.Collectibles.Select(collectible => collectible.Key).ToList(); - - var manifestInventoryItems = new List(); - foreach (var destinyInventoryItemDefinition in manifestInventoryItemIDs) - { - _bungieClient.Repository.TryGetDestinyDefinition( - (uint)destinyInventoryItemDefinition!, out var result); - - manifestInventoryItems.Add(result); - } - - var manifestCollectibles = new List(); - foreach (var definitionHashPointer in manifestCollectibleIDs) - { - _bungieClient.Repository.TryGetDestinyDefinition( - (uint)definitionHashPointer.Hash!, out var result); - - manifestCollectibles.Add(result); - } - - foreach (var collectible in from collectible in manifestCollectibles - where !collectible.Redacted - where !string.IsNullOrEmpty(collectible.DisplayProperties.Name) - from manifestCollectibleParentNodeHash in collectible.ParentNodes - where EmblemCats.EmblemCatList.Contains((EmblemCat)manifestCollectibleParentNodeHash.Hash!) - select collectible) - { - emblemCount++; - - var value = profile.Response.ProfileCollectibles.Data.Collectibles[collectible.Hash]; - - foreach (var unused in from emblem in manifestInventoryItems - where emblem.Collectible.Hash == collectible.Hash - where value.State.HasFlag(DestinyCollectibleState.NotAcquired) - where !emblemList.Contains(collectible) - select emblem) emblemList.Add(collectible); - - if (value.State.HasFlag(DestinyCollectibleState.Invisible) && - !value.State.HasFlag(DestinyCollectibleState.NotAcquired)) - if (!emblemList.Contains(collectible)) - emblemList.Add(collectible); - - // ReSharper disable once InvertIf - if (value.State.HasFlag(DestinyCollectibleState.UniquenessViolation) && - value.State.HasFlag(DestinyCollectibleState.NotAcquired)) - if (!emblemList.Contains(collectible)) - emblemList.Add(collectible); - } - - var sortedList = emblemList.OrderBy(o => o.DisplayProperties.Name).ToList(); - - var embed = Embeds.MakeBuilder(); - - embed.Title = requestedProfile.BungieName; - embed.Url = - $"https://www.bungie.net/7/en/User/Profile/{(int)profile.Response.Profile.Data.UserInfo.MembershipType}/" + - profile.Response.Profile.Data.UserInfo.MembershipId; - embed.ThumbnailUrl = BotVariables.BungieBaseUrl + profile.Response.Characters.Data.First().Value.EmblemPath; - - if (sortedList.Count == 0) - { - embed.Description = "Account has no shared emblems."; - } - else - { - embed.Description = "**Account shared emblems:**\n"; - - foreach (var emblemDefinition in sortedList) - embed.Description += - $"> [{emblemDefinition.DisplayProperties.Name}](https://emblem.report/{emblemDefinition.Item.Hash})\n"; - } - - embed.AddField("Parsed", $"> {emblemCount}", true); - embed.AddField("Shared", $"> {sortedList.Count}", true); - - await FollowupAsync(embed: embed.Build()); - } - - [SlashCommand("rarest", "Gets the top rarest emblems in collections.")] - public async Task EmblemRarest( - [Summary("count", "Number of rarest emblems to fetch. (default = 5, between 1 and 50)")] - int count = 5, - [Summary("bungie-name", - "Bungie name of the requested user. (name#1234)")] - string bungieTag = "") - { - await DeferAsync(); - - if (count is <= 0 or > 50) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = - $"`{count}` is not a valid choice.\nTry again with a value between 1 and 50."; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - if (!await BungieApiUtils.CheckApi(_bungieClient)) - throw new Exception("Bungie API is down or unresponsive."); - - if (!string.IsNullOrEmpty(bungieTag) && !bungieTag.Contains('#')) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = - $"`{bungieTag}` is not a correct format for a Bungie name.\nTry again with the `#` format."; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var requestedProfile = - await ProfileHelper.GetRequestedProfile(bungieTag, Context.User.Id, _userDb, _bungieClient); - - if (!string.IsNullOrEmpty(requestedProfile.Error)) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = requestedProfile.Error; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var profile = await _bungieClient.ApiAccess.Destiny2.GetProfile(requestedProfile.MembershipType, - requestedProfile.MembershipId, new[] - { - DestinyComponentType.Collectibles, DestinyComponentType.Profiles - }); - - // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract - // Note to self, bungie privacy sucks ass and always reports privacy as private. - if (profile.Response.ProfileCollectibles.Data == null) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = $"`{bungieTag}` has their collections set to private, unable to parse emblems."; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var manifestCollectibleIDs = AddEmblems(profile.Response); - - switch (requestedProfile.MembershipId) - { - // Moonie - case 4611686018471516071: - profile = await _bungieClient.ApiAccess.Destiny2.GetProfile( - BungieMembershipType.TigerSteam, 4611686018500337909, - new[] - { - DestinyComponentType.Collectibles, DestinyComponentType.Profiles - }); - - manifestCollectibleIDs.AddRange(AddEmblems(profile.Response)); - break; - // Zempp - case 4611686018432393645: - profile = await _bungieClient.ApiAccess.Destiny2.GetProfile( - BungieMembershipType.TigerPsn, 4611686018475371052, - new[] - { - DestinyComponentType.Collectibles, DestinyComponentType.Profiles - }); - - manifestCollectibleIDs.AddRange(AddEmblems(profile.Response)); - - profile = await _bungieClient.ApiAccess.Destiny2.GetProfile( - BungieMembershipType.TigerSteam, 4611686018483360936, - new[] - { - DestinyComponentType.Collectibles, DestinyComponentType.Profiles - }); - - manifestCollectibleIDs.AddRange(AddEmblems(profile.Response)); - break; - } - - var manifestCollectibles = new List(); - foreach (var definitionHashPointer in manifestCollectibleIDs) - { - _bungieClient.Repository.TryGetDestinyDefinition( - (uint)definitionHashPointer.Hash!, out var result); - - if (!result.Redacted && !string.IsNullOrEmpty(result.DisplayProperties.Name)) - manifestCollectibles.AddRange(from definitionParentNode in result.ParentNodes - where EmblemCats.EmblemCatList.Contains((EmblemCat)definitionParentNode.Hash!) - select result); - } - - string jsonString; - - try - { - var collectiblesData = new - { - collectibles = manifestCollectibles.Select(x => x.Hash).ToList() - }; - - using var client = new HttpClient(); - client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; Felicity/1.0)"); - client.DefaultRequestHeaders.Add("X-API-KEY", _botOptions.Value.EmblemReportApiKey); - - var json = JsonSerializer.Serialize(collectiblesData); - var content = new StringContent(json, Encoding.UTF8, "application/json"); - - var response = await client.PostAsync($"https://emblem.report/api/getRarestEmblems?limit={count}", content); - response.EnsureSuccessStatusCode(); - - var responseData = await response.Content.ReadAsStringAsync(); - jsonString = responseData; - } - catch (Exception error) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = error.Message; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var emblemResponse = EmblemReport.EmblemResponse.FromJson(jsonString); - if (emblemResponse?.Data == null) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = "Failed to parse response from server."; - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var embed = new EmbedBuilder - { - Title = requestedProfile.BungieName, - Url = - $"https://www.bungie.net/7/en/User/Profile/{(int)profile.Response.Profile.Data.UserInfo.MembershipType}/" + - profile.Response.Profile.Data.UserInfo.MembershipId, - Color = Color.Purple, - Footer = Embeds.MakeFooter(), - Description = - $"Here are the {count} rarest emblems in collections for this user.\nData provided by [emblem.report](https://emblem.report).\n\n" - }; - - var i = 1; - - foreach (var emblem in emblemResponse.Data) - if (_bungieClient.Repository.TryGetDestinyDefinition(emblem.CollectibleHash, - out var emblemDef)) - { - var sb = new StringBuilder(); - embed.Description += count.ToString().Length switch - { - < 10 => $"> {i}. ", - _ => $"> {i,2}. " - }; - - sb.Append(emblem.Acquisition.ToString("N0").PadLeft(7)); - - embed.Description += - $"`{sb}` - " + - $"[{emblemDef.DisplayProperties.Name}](https://emblem.report/{emblemDef.Item.Select(x => x.Hash)}) " + - $"({emblem.Percentage}%)\n"; - - if (embed.Description.Length <= 3850) - { - i++; - continue; - } - - embed.Description += $"\n\n**Requested size is too long, response has been truncated to {i} emblems**."; - embed.Description = - embed.Description.Replace($"Here are the {count} rarest", - $"Here are the {i} rarest"); // Don't mind me. - break; - } - - await FollowupAsync(embed: embed.Build()); - } - - private static List> AddEmblems( - DestinyProfileResponse profileResponse) - { - var manifestCollectibleIDs = - (from destinyCollectibleComponent in profileResponse.ProfileCollectibles.Data.Collectibles - where !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.UniquenessViolation) || - !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) - where !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.Invisible) || - destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) - where !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) - select destinyCollectibleComponent.Key).ToList(); - - foreach (var destinyCollectibleComponent in profileResponse.CharacterCollectibles.Data) - manifestCollectibleIDs.AddRange(from collectibleComponent in destinyCollectibleComponent.Value.Collectibles - where !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.UniquenessViolation) || - !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) - where !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.Invisible) || - collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) - where !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) - select collectibleComponent.Key); - - return manifestCollectibleIDs; - } -} \ No newline at end of file +using System.Text; +using System.Text.Json; +using Discord; +using Discord.Interactions; +using DotNetBungieAPI.Extensions; +using DotNetBungieAPI.Models; +using DotNetBungieAPI.Models.Destiny; +using DotNetBungieAPI.Models.Destiny.Definitions.Collectibles; +using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; +using DotNetBungieAPI.Models.Destiny.Responses; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Models; +using Felicity.Options; +using Felicity.Util; +using Felicity.Util.Enums; +using Microsoft.Extensions.Options; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace Felicity.DiscordCommands.Interactions; + +[Group("emblem", "Various lookup commands for Destiny 2.")] +public class EmblemCommands : InteractionModuleBase +{ + private readonly IBungieClient _bungieClient; + private readonly UserDb _userDb; + private readonly IConfiguration _configuration; + + public EmblemCommands(IBungieClient bungieClient, UserDb userDb, IConfiguration configuration) + { + _bungieClient = bungieClient; + _userDb = userDb; + _configuration = configuration; + } + + [SlashCommand("shares", "Look up account shared emblems of a player.")] + public async Task EmblemShares( + [Summary("bungie-name", + "Bungie name of the requested user (name#1234).")] + string bungieTag = "") + { + await DeferAsync(); + + if (!await BungieApiUtils.CheckApi(_bungieClient)) + throw new Exception("Bungie API is down or unresponsive."); + + if (!string.IsNullOrEmpty(bungieTag) && !bungieTag.Contains('#')) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = + $"`{bungieTag}` is not a correct format for a Bungie name.\nTry again with the `#` format."; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var requestedProfile = + await ProfileHelper.GetRequestedProfile(bungieTag, Context.User.Id, _userDb, _bungieClient); + + if (!string.IsNullOrEmpty(requestedProfile.Error)) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = requestedProfile.Error; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var profile = await _bungieClient.ApiAccess.Destiny2.GetProfile(requestedProfile.MembershipType, + requestedProfile.MembershipId, new[] + { + DestinyComponentType.Characters, DestinyComponentType.Profiles, DestinyComponentType.Collectibles + }); + + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + // Note to self, bungie privacy sucks ass and always reports privacy as private. + if (profile.Response.ProfileCollectibles.Data == null) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = $"`{bungieTag}` has their collections set to private, unable to parse emblems."; + + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var emblemCount = 0; + var emblemList = new List(); + + var manifestInventoryItemIDs = profile.Response.Characters.Data + .Select(destinyCharacterComponent => destinyCharacterComponent.Value.Emblem.Hash).ToList(); + var manifestCollectibleIDs = + profile.Response.ProfileCollectibles.Data.Collectibles.Select(collectible => collectible.Key).ToList(); + + var manifestInventoryItems = new List(); + foreach (var destinyInventoryItemDefinition in manifestInventoryItemIDs) + { + _bungieClient.Repository.TryGetDestinyDefinition( + (uint)destinyInventoryItemDefinition!, out var result); + + manifestInventoryItems.Add(result); + } + + var manifestCollectibles = new List(); + foreach (var definitionHashPointer in manifestCollectibleIDs) + { + _bungieClient.Repository.TryGetDestinyDefinition( + (uint)definitionHashPointer.Hash!, out var result); + + manifestCollectibles.Add(result); + } + + foreach (var collectible in from collectible in manifestCollectibles + where !collectible.Redacted + where !string.IsNullOrEmpty(collectible.DisplayProperties.Name) + from manifestCollectibleParentNodeHash in collectible.ParentNodes + where EmblemCats.EmblemCatList.Contains((EmblemCat)manifestCollectibleParentNodeHash.Hash!) + select collectible) + { + emblemCount++; + + var value = profile.Response.ProfileCollectibles.Data.Collectibles[collectible.Hash]; + + foreach (var unused in from emblem in manifestInventoryItems + where emblem.Collectible.Hash == collectible.Hash + where value.State.HasFlag(DestinyCollectibleState.NotAcquired) + where !emblemList.Contains(collectible) + select emblem) emblemList.Add(collectible); + + if (value.State.HasFlag(DestinyCollectibleState.Invisible) && + !value.State.HasFlag(DestinyCollectibleState.NotAcquired)) + if (!emblemList.Contains(collectible)) + emblemList.Add(collectible); + + // ReSharper disable once InvertIf + if (value.State.HasFlag(DestinyCollectibleState.UniquenessViolation) && + value.State.HasFlag(DestinyCollectibleState.NotAcquired)) + if (!emblemList.Contains(collectible)) + emblemList.Add(collectible); + } + + var sortedList = emblemList.OrderBy(o => o.DisplayProperties.Name).ToList(); + + var embed = Embeds.MakeBuilder(); + + embed.Title = requestedProfile.BungieName; + embed.Url = + $"https://www.bungie.net/7/en/User/Profile/{(int)profile.Response.Profile.Data.UserInfo.MembershipType}/" + + profile.Response.Profile.Data.UserInfo.MembershipId; + embed.ThumbnailUrl = BotVariables.BungieBaseUrl + profile.Response.Characters.Data.First().Value.EmblemPath; + + if (sortedList.Count == 0) + { + embed.Description = "Account has no shared emblems."; + } + else + { + embed.Description = "**Account shared emblems:**\n"; + + foreach (var emblemDefinition in sortedList) + embed.Description += + $"> [{emblemDefinition.DisplayProperties.Name}](https://emblem.report/{emblemDefinition.Item.Hash})\n"; + } + + embed.AddField("Parsed", $"> {emblemCount}", true); + embed.AddField("Shared", $"> {sortedList.Count}", true); + + await FollowupAsync(embed: embed.Build()); + } + + [SlashCommand("rarest", "Gets the top rarest emblems in collections.")] + public async Task EmblemRarest( + [Summary("count", "Number of rarest emblems to fetch. (default = 5, between 1 and 50)")] + int count = 5, + [Summary("bungie-name", + "Bungie name of the requested user. (name#1234)")] + string bungieTag = "") + { + await DeferAsync(); + + if (count is <= 0 or > 50) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = + $"`{count}` is not a valid choice.\nTry again with a value between 1 and 50."; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + if (!await BungieApiUtils.CheckApi(_bungieClient)) + throw new Exception("Bungie API is down or unresponsive."); + + if (!string.IsNullOrEmpty(bungieTag) && !bungieTag.Contains('#')) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = + $"`{bungieTag}` is not a correct format for a Bungie name.\nTry again with the `#` format."; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var requestedProfile = + await ProfileHelper.GetRequestedProfile(bungieTag, Context.User.Id, _userDb, _bungieClient); + + if (!string.IsNullOrEmpty(requestedProfile.Error)) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = requestedProfile.Error; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var profile = await _bungieClient.ApiAccess.Destiny2.GetProfile(requestedProfile.MembershipType, + requestedProfile.MembershipId, new[] + { + DestinyComponentType.Collectibles, DestinyComponentType.Profiles + }); + + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + // Note to self, bungie privacy sucks ass and always reports privacy as private. + if (profile.Response.ProfileCollectibles.Data == null) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = $"`{bungieTag}` has their collections set to private, unable to parse emblems."; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var manifestCollectibleIDs = AddEmblems(profile.Response); + + switch (requestedProfile.MembershipId) + { + // Moonie + case 4611686018471516071: + profile = await _bungieClient.ApiAccess.Destiny2.GetProfile( + BungieMembershipType.TigerSteam, 4611686018500337909, + new[] + { + DestinyComponentType.Collectibles, DestinyComponentType.Profiles + }); + + manifestCollectibleIDs.AddRange(AddEmblems(profile.Response)); + break; + // Zempp + case 4611686018432393645: + profile = await _bungieClient.ApiAccess.Destiny2.GetProfile( + BungieMembershipType.TigerPsn, 4611686018475371052, + new[] + { + DestinyComponentType.Collectibles, DestinyComponentType.Profiles + }); + + manifestCollectibleIDs.AddRange(AddEmblems(profile.Response)); + + profile = await _bungieClient.ApiAccess.Destiny2.GetProfile( + BungieMembershipType.TigerSteam, 4611686018483360936, + new[] + { + DestinyComponentType.Collectibles, DestinyComponentType.Profiles + }); + + manifestCollectibleIDs.AddRange(AddEmblems(profile.Response)); + break; + } + + var manifestCollectibles = new List(); + foreach (var definitionHashPointer in manifestCollectibleIDs) + { + _bungieClient.Repository.TryGetDestinyDefinition( + (uint)definitionHashPointer.Hash!, out var result); + + if (!result.Redacted && !string.IsNullOrEmpty(result.DisplayProperties.Name)) + manifestCollectibles.AddRange(from definitionParentNode in result.ParentNodes + where EmblemCats.EmblemCatList.Contains((EmblemCat)definitionParentNode.Hash!) + select result); + } + + string jsonString; + + try + { + var collectiblesData = new + { + collectibles = manifestCollectibles.Select(x => x.Hash).ToList() + }; + + using var client = new HttpClient(); + client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; Felicity/1.0)"); + client.DefaultRequestHeaders.Add("x-api-key", _configuration["Bungie:EmblemReportApiKey"]); + + var json = JsonSerializer.Serialize(collectiblesData); + var content = new StringContent(json, Encoding.UTF8, "application/json"); + + var response = await client.PostAsync($"https://emblem.report/api/getRarestEmblems?limit={count}", content); + response.EnsureSuccessStatusCode(); + + var responseData = await response.Content.ReadAsStringAsync(); + jsonString = responseData; + } + catch (Exception error) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = error.Message; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var emblemResponse = EmblemReport.EmblemResponse.FromJson(jsonString); + if (emblemResponse?.Data == null) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = "Failed to parse response from server."; + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var embed = new EmbedBuilder + { + Title = requestedProfile.BungieName, + Url = + $"https://www.bungie.net/7/en/User/Profile/{(int)profile.Response.Profile.Data.UserInfo.MembershipType}/" + + profile.Response.Profile.Data.UserInfo.MembershipId, + Color = Color.Purple, + Footer = Embeds.MakeFooter(), + Description = + $"Here are the {count} rarest emblems in collections for this user.\nData provided by [emblem.report](https://emblem.report).\n\n" + }; + + var i = 1; + + foreach (var emblem in emblemResponse.Data) + if (_bungieClient.Repository.TryGetDestinyDefinition(emblem.CollectibleHash, + out var emblemDef)) + { + var sb = new StringBuilder(); + embed.Description += count.ToString().Length switch + { + < 10 => $"> {i}. ", + _ => $"> {i,2}. " + }; + + sb.Append(emblem.Acquisition.ToString("N0").PadLeft(7)); + + embed.Description += + $"`{sb}` - " + + $"[{emblemDef.DisplayProperties.Name}](https://emblem.report/{emblemDef.Item.Select(x => x.Hash)}) " + + $"({emblem.Percentage}%)\n"; + + if (embed.Description.Length <= 3850) + { + i++; + continue; + } + + embed.Description += $"\n\n**Requested size is too long, response has been truncated to {i} emblems**."; + embed.Description = + embed.Description.Replace($"Here are the {count} rarest", + $"Here are the {i} rarest"); // Don't mind me. + break; + } + + await FollowupAsync(embed: embed.Build()); + } + + private static List> AddEmblems( + DestinyProfileResponse profileResponse) + { + var manifestCollectibleIDs = + (from destinyCollectibleComponent in profileResponse.ProfileCollectibles.Data.Collectibles + where !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.UniquenessViolation) || + !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) + where !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.Invisible) || + destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) + where !destinyCollectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) + select destinyCollectibleComponent.Key).ToList(); + + foreach (var destinyCollectibleComponent in profileResponse.CharacterCollectibles.Data) + manifestCollectibleIDs.AddRange(from collectibleComponent in destinyCollectibleComponent.Value.Collectibles + where !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.UniquenessViolation) || + !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) + where !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.Invisible) || + collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) + where !collectibleComponent.Value.State.HasFlag(DestinyCollectibleState.NotAcquired) + select collectibleComponent.Key); + + return manifestCollectibleIDs; + } +} diff --git a/Felicity/DiscordCommands/Interactions/LootCommands.cs b/Felicity/DiscordCommands/Interactions/LootCommands.cs index e486d97..5b1afbc 100644 --- a/Felicity/DiscordCommands/Interactions/LootCommands.cs +++ b/Felicity/DiscordCommands/Interactions/LootCommands.cs @@ -1,106 +1,106 @@ -using Discord; -using Discord.Interactions; -using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Util; -using Felicity.Util.Enums; -using ActivityType = Felicity.Util.Enums.ActivityType; - -// ReSharper disable UnusedType.Global -// ReSharper disable UnusedMember.Global - -namespace Felicity.DiscordCommands.Interactions; - -public class LootCommands : InteractionModuleBase -{ - private readonly IBungieClient _bungieClient; - - public LootCommands(IBungieClient bungieClient) - { - _bungieClient = bungieClient; - } - - [SlashCommand("loot-table", "Get loot tables from dungeons or raids.")] - public async Task LootTable([Autocomplete(typeof(LootTableAutocomplete))] string lootTable) - { - await DeferAsync(); - - var requestedLootTable = LootTables.KnownTables.FirstOrDefault(x => x.Name == lootTable); - if (requestedLootTable?.Loot == null) - { - var errorEmbed = Embeds.MakeErrorEmbed(); - errorEmbed.Description = "Unable to find requested loot table."; - - await FollowupAsync(embed: errorEmbed.Build()); - return; - } - - var embed = Embeds.MakeBuilder(); - embed.Title = $"{requestedLootTable.Name} loot table:"; - embed.Description = Format.Italics(requestedLootTable.Description); - - if (requestedLootTable.ActivityType == ActivityType.Dungeon) - embed.Description += - $"\n\n{Format.Bold("Secret chests can drop any previously acquired armor and weapons.")}"; - - embed.ThumbnailUrl = requestedLootTable.ActivityType switch - { - ActivityType.Dungeon => BotVariables.Images.DungeonIcon, - ActivityType.Raid => BotVariables.Images.RaidIcon, - _ => string.Empty - }; - - // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator - foreach (var table in requestedLootTable.Loot) - { - if (table.LootIds == null) - continue; - - if (embed.Fields.Count is 2 or 5) - embed.AddField("\u200b", '\u200b'); - - embed.AddField(table.EncounterName, BuildDrops(_bungieClient, table.LootIds), true); - } - - await FollowupAsync(embed: embed.Build()); - } - - private static string BuildDrops(IBungieClient bungieClient, List tableLootIds) - { - var result = string.Empty; - - foreach (var tableLootId in tableLootIds) - { - switch (tableLootId) - { - case (uint)Armor.Everything: - result += "\n <:CS:996724235634491523> All Possible Drops"; - continue; - case (uint)Armor.Helmet: - result += "<:helmet:996490149728899122> "; - continue; - case (uint)Armor.Gloves: - result += "<:gloves:996490148025995385> "; - continue; - case (uint)Armor.Chest: - result += "<:chest:996490146922901655> "; - continue; - case (uint)Armor.Boots: - result += "<:boots:996490145224200292> "; - continue; - case (uint)Armor.Class: - result += "<:class:996490144066572288> "; - continue; - } - - if (bungieClient.Repository.TryGetDestinyDefinition(tableLootId, - out var manifestItem)) - result += - $"\n{EmoteHelper.GetItemType(manifestItem)} " + - $"[{manifestItem.DisplayProperties.Name.Replace("(Timelost)", "(TL)")}]" + - $"({MiscUtils.GetLightGgLink(tableLootId)})"; - } - - return result; - } +using Discord; +using Discord.Interactions; +using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Util; +using Felicity.Util.Enums; +using ActivityType = Felicity.Util.Enums.ActivityType; + +// ReSharper disable UnusedType.Global +// ReSharper disable UnusedMember.Global + +namespace Felicity.DiscordCommands.Interactions; + +public class LootCommands : InteractionModuleBase +{ + private readonly IBungieClient _bungieClient; + + public LootCommands(IBungieClient bungieClient) + { + _bungieClient = bungieClient; + } + + [SlashCommand("loot-table", "Get loot tables from dungeons or raids.")] + public async Task LootTable([Autocomplete(typeof(LootTableAutocomplete))] string lootTable) + { + await DeferAsync(); + + var requestedLootTable = LootTables.KnownTables.FirstOrDefault(x => x.Name == lootTable); + if (requestedLootTable?.Loot == null) + { + var errorEmbed = Embeds.MakeErrorEmbed(); + errorEmbed.Description = "Unable to find requested loot table."; + + await FollowupAsync(embed: errorEmbed.Build()); + return; + } + + var embed = Embeds.MakeBuilder(); + embed.Title = $"{requestedLootTable.Name} loot table:"; + embed.Description = Format.Italics(requestedLootTable.Description); + + if (requestedLootTable.ActivityType == ActivityType.Dungeon) + embed.Description += + $"\n\n{Format.Bold("Secret chests can drop any previously acquired armor and weapons.")}"; + + embed.ThumbnailUrl = requestedLootTable.ActivityType switch + { + ActivityType.Dungeon => BotVariables.Images.DungeonIcon, + ActivityType.Raid => BotVariables.Images.RaidIcon, + _ => string.Empty + }; + + // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator + foreach (var table in requestedLootTable.Loot) + { + if (table.LootIds == null) + continue; + + if (embed.Fields.Count is 2 or 5) + embed.AddField("\u200b", '\u200b'); + + embed.AddField(table.EncounterName, BuildDrops(_bungieClient, table.LootIds), true); + } + + await FollowupAsync(embed: embed.Build()); + } + + private static string BuildDrops(IBungieClient bungieClient, List tableLootIds) + { + var result = string.Empty; + + foreach (var tableLootId in tableLootIds) + { + switch (tableLootId) + { + case (uint)Armor.Everything: + result += "\n <:CS:996724235634491523> All Possible Drops"; + continue; + case (uint)Armor.Helmet: + result += "<:helmet:996490149728899122> "; + continue; + case (uint)Armor.Gloves: + result += "<:gloves:996490148025995385> "; + continue; + case (uint)Armor.Chest: + result += "<:chest:996490146922901655> "; + continue; + case (uint)Armor.Boots: + result += "<:boots:996490145224200292> "; + continue; + case (uint)Armor.Class: + result += "<:class:996490144066572288> "; + continue; + } + + if (bungieClient.Repository.TryGetDestinyDefinition(tableLootId, + out var manifestItem)) + result += + $"\n{EmoteHelper.GetItemType(manifestItem)} " + + $"[{manifestItem.DisplayProperties.Name.Replace("(Timelost)", "(TL)")}]" + + $"({MiscUtils.GetLightGgLink(tableLootId)})"; + } + + return result; + } } \ No newline at end of file diff --git a/Felicity/DiscordCommands/Interactions/MetricsCommands.cs b/Felicity/DiscordCommands/Interactions/MetricsCommands.cs index 8b9d920..8bf2a24 100644 --- a/Felicity/DiscordCommands/Interactions/MetricsCommands.cs +++ b/Felicity/DiscordCommands/Interactions/MetricsCommands.cs @@ -1,64 +1,64 @@ -using Discord.Interactions; -using DotNetBungieAPI.Extensions; -using DotNetBungieAPI.Models.Destiny; -using DotNetBungieAPI.Models.Destiny.Definitions.Metrics; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Models; -using Felicity.Util; - -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global - -namespace Felicity.DiscordCommands.Interactions; - -[Preconditions.RequireOAuth] -public class MetricsCommands : InteractionModuleBase -{ - private readonly IBungieClient _bungieClient; - private readonly UserDb _userDb; - - public MetricsCommands(IBungieClient bungieClient, UserDb userDb) - { - _bungieClient = bungieClient; - _userDb = userDb; - } - - [SlashCommand("metrics", "Fetch metrics from your Destiny profile.")] - public async Task Metrics( - [Autocomplete(typeof(MetricAutocomplete))] [Summary("query", "Specific metric you want to pull values for.")] - uint metricId) - { - if (!await BungieApiUtils.CheckApi(_bungieClient)) - throw new Exception("Bungie API is down or unresponsive."); - - var currentUser = _userDb.Users.FirstOrDefault(x => x.DiscordId == Context.User.Id); - if (currentUser == null) - { - await FollowupAsync("Failed to fetch user profile."); - return; - } - - if (!_bungieClient.Repository.TryGetDestinyDefinition(metricId, - out var metricDefinition)) - { - await FollowupAsync("Failed to fetch metrics."); - return; - } - - var profileMetrics = await _bungieClient.ApiAccess.Destiny2.GetProfile(currentUser.DestinyMembershipType, - currentUser.DestinyMembershipId, new[] - { - DestinyComponentType.Metrics - }, currentUser.GetTokenData()); - - var value = profileMetrics.Response.Metrics.Data.Metrics[metricId].ObjectiveProgress.Progress - ?.FormatUIDisplayValue(profileMetrics.Response.Metrics.Data.Metrics[metricId].ObjectiveProgress.Objective - .GetValueOrNull()!); - - var embed = Embeds.MakeBuilder(); - embed.AddField(metricDefinition.DisplayProperties.Name, value); - embed.AddField("Objective", metricDefinition.TrackingObjective.Select(x => x.ProgressDescription)); - - await FollowupAsync(embed: embed.Build()); - } +using Discord.Interactions; +using DotNetBungieAPI.Extensions; +using DotNetBungieAPI.Models.Destiny; +using DotNetBungieAPI.Models.Destiny.Definitions.Metrics; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Models; +using Felicity.Util; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace Felicity.DiscordCommands.Interactions; + +[Preconditions.RequireOAuth] +public class MetricsCommands : InteractionModuleBase +{ + private readonly IBungieClient _bungieClient; + private readonly UserDb _userDb; + + public MetricsCommands(IBungieClient bungieClient, UserDb userDb) + { + _bungieClient = bungieClient; + _userDb = userDb; + } + + [SlashCommand("metrics", "Fetch metrics from your Destiny profile.")] + public async Task Metrics( + [Autocomplete(typeof(MetricAutocomplete))] [Summary("query", "Specific metric you want to pull values for.")] + uint metricId) + { + if (!await BungieApiUtils.CheckApi(_bungieClient)) + throw new Exception("Bungie API is down or unresponsive."); + + var currentUser = _userDb.Users.FirstOrDefault(x => x.DiscordId == Context.User.Id); + if (currentUser == null) + { + await FollowupAsync("Failed to fetch user profile."); + return; + } + + if (!_bungieClient.Repository.TryGetDestinyDefinition(metricId, + out var metricDefinition)) + { + await FollowupAsync("Failed to fetch metrics."); + return; + } + + var profileMetrics = await _bungieClient.ApiAccess.Destiny2.GetProfile(currentUser.DestinyMembershipType, + currentUser.DestinyMembershipId, new[] + { + DestinyComponentType.Metrics + }, currentUser.GetTokenData()); + + var value = profileMetrics.Response.Metrics.Data.Metrics[metricId].ObjectiveProgress.Progress + ?.FormatUIDisplayValue(profileMetrics.Response.Metrics.Data.Metrics[metricId].ObjectiveProgress.Objective + .GetValueOrNull()!); + + var embed = Embeds.MakeBuilder(); + embed.AddField(metricDefinition.DisplayProperties.Name, value); + embed.AddField("Objective", metricDefinition.TrackingObjective.Select(x => x.ProgressDescription)); + + await FollowupAsync(embed: embed.Build()); + } } \ No newline at end of file diff --git a/Felicity/DiscordCommands/Interactions/PbCommands.cs b/Felicity/DiscordCommands/Interactions/PbCommands.cs index 503a128..96269f5 100644 --- a/Felicity/DiscordCommands/Interactions/PbCommands.cs +++ b/Felicity/DiscordCommands/Interactions/PbCommands.cs @@ -1,72 +1,72 @@ -using System.Text; -using Discord.Interactions; -using DotNetBungieAPI.Extensions; -using DotNetBungieAPI.HashReferences; -using DotNetBungieAPI.Models.Destiny; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Models; -using Felicity.Util; - -// ReSharper disable UnusedType.Global -// ReSharper disable UnusedMember.Global - -namespace Felicity.DiscordCommands.Interactions; - -[Preconditions.RequireOAuth] -[Group("pb", "Gets your personal best times for each category.")] -public class PbCommands : InteractionModuleBase -{ - private readonly IBungieClient _bungieClient; - private readonly UserDb _userDb; - - public PbCommands(IBungieClient bungieClient, UserDb userDb) - { - _bungieClient = bungieClient; - _userDb = userDb; - } - - [SlashCommand("raids", "Gets your fastest raids.")] - public async Task PbRaids() - { - var currentUser = _userDb.Users.FirstOrDefault(x => x.DiscordId == Context.User.Id); - if (currentUser == null) - { - await FollowupAsync("Failed to fetch user profile."); - return; - } - - var profileMetrics = await _bungieClient.ApiAccess.Destiny2.GetProfile(currentUser.DestinyMembershipType, - currentUser.DestinyMembershipId, new[] - { - DestinyComponentType.Metrics - }, currentUser.GetTokenData()); - - var value = new StringBuilder(); - var metricList = new List> - { - new("Last Wish", DefinitionHashes.Metrics.LastWishTimeTrial_552340969), - new("Garden of Salvation", DefinitionHashes.Metrics.KingsFallTimeTrial_399420098), - new("Deep Stone Crypt", DefinitionHashes.Metrics.DeepStoneCryptTimeTrial_3679202587), - new("Vault of Glass", DefinitionHashes.Metrics.VaultofGlassTimeTrial_905219689), - new("Vow of the Disciple", DefinitionHashes.Metrics.VowoftheDiscipleTimeTrial_3775579868), - new("King's Fall", DefinitionHashes.Metrics.KingsFallTimeTrial_399420098), - new("Root of Nightmares", DefinitionHashes.Metrics.RootofNightmaresTimeTrial_58319253) - }; - - foreach (var metric in metricList) - { - var time = profileMetrics.Response.Metrics.Data.Metrics[metric.Value].ObjectiveProgress.Progress - ?.FormatUIDisplayValue(profileMetrics.Response.Metrics.Data.Metrics[metric.Value].ObjectiveProgress - .Objective.GetValueOrNull()!); - value.Append($"> `{time}` - **{metric.Key}**\n"); - } - - var embed = Embeds.MakeBuilder(); - embed.Title = $"Personal best clear times for {currentUser.BungieName}"; - embed.Description = - "⚠️ These values are only what in-game stat trackers show, real times as well as checkpoint vs full clears and lowmans will be available in a future update.\n\n" - + value; - - await FollowupAsync(embed: embed.Build()); - } +using System.Text; +using Discord.Interactions; +using DotNetBungieAPI.Extensions; +using DotNetBungieAPI.HashReferences; +using DotNetBungieAPI.Models.Destiny; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Models; +using Felicity.Util; + +// ReSharper disable UnusedType.Global +// ReSharper disable UnusedMember.Global + +namespace Felicity.DiscordCommands.Interactions; + +[Preconditions.RequireOAuth] +[Group("pb", "Gets your personal best times for each category.")] +public class PbCommands : InteractionModuleBase +{ + private readonly IBungieClient _bungieClient; + private readonly UserDb _userDb; + + public PbCommands(IBungieClient bungieClient, UserDb userDb) + { + _bungieClient = bungieClient; + _userDb = userDb; + } + + [SlashCommand("raids", "Gets your fastest raids.")] + public async Task PbRaids() + { + var currentUser = _userDb.Users.FirstOrDefault(x => x.DiscordId == Context.User.Id); + if (currentUser == null) + { + await FollowupAsync("Failed to fetch user profile."); + return; + } + + var profileMetrics = await _bungieClient.ApiAccess.Destiny2.GetProfile(currentUser.DestinyMembershipType, + currentUser.DestinyMembershipId, new[] + { + DestinyComponentType.Metrics + }, currentUser.GetTokenData()); + + var value = new StringBuilder(); + var metricList = new List> + { + new("Last Wish", DefinitionHashes.Metrics.LastWishTimeTrial_552340969), + new("Garden of Salvation", DefinitionHashes.Metrics.KingsFallTimeTrial_399420098), + new("Deep Stone Crypt", DefinitionHashes.Metrics.DeepStoneCryptTimeTrial_3679202587), + new("Vault of Glass", DefinitionHashes.Metrics.VaultofGlassTimeTrial_905219689), + new("Vow of the Disciple", DefinitionHashes.Metrics.VowoftheDiscipleTimeTrial_3775579868), + new("King's Fall", DefinitionHashes.Metrics.KingsFallTimeTrial_399420098), + new("Root of Nightmares", DefinitionHashes.Metrics.RootofNightmaresTimeTrial_58319253) + }; + + foreach (var metric in metricList) + { + var time = profileMetrics.Response.Metrics.Data.Metrics[metric.Value].ObjectiveProgress.Progress + ?.FormatUIDisplayValue(profileMetrics.Response.Metrics.Data.Metrics[metric.Value].ObjectiveProgress + .Objective.GetValueOrNull()!); + value.Append($"> `{time}` - **{metric.Key}**\n"); + } + + var embed = Embeds.MakeBuilder(); + embed.Title = $"Personal best clear times for {currentUser.BungieName}"; + embed.Description = + "⚠️ These values are only what in-game stat trackers show, real times as well as checkpoint vs full clears and lowmans will be available in a future update.\n\n" + + value; + + await FollowupAsync(embed: embed.Build()); + } } \ No newline at end of file diff --git a/Felicity/DiscordCommands/Interactions/RollFinderCommands.cs b/Felicity/DiscordCommands/Interactions/RollFinderCommands.cs index 8603051..580d51d 100644 --- a/Felicity/DiscordCommands/Interactions/RollFinderCommands.cs +++ b/Felicity/DiscordCommands/Interactions/RollFinderCommands.cs @@ -1,165 +1,165 @@ -using System.Text; -using Discord; -using Discord.Interactions; -using DotNetBungieAPI.Models.Destiny; -using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Models; -using Felicity.Util; -using Humanizer; - -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global - -namespace Felicity.DiscordCommands.Interactions; - -public class RollFinderCommands : InteractionModuleBase -{ - private readonly IBungieClient _bungieClient; - - public RollFinderCommands(IBungieClient bungieClient) - { - _bungieClient = bungieClient; - } - - [SlashCommand("roll-finder", "Find a recommended roll for a specific weapon from a curated list.")] - public async Task RollFinder( - [Summary("game-mode", "Game mode to suggest rolls for:")] [Choice("PvE", 0)] [Choice("PvP", 1)] - int gameMode, - [Autocomplete(typeof(RollFinderAutocomplete))] [Summary("weapon-name", "Name of the weapon to search for:")] - uint weaponId) - { - await DeferAsync(); - - var weaponRollList = await ProcessRollData.FromJsonAsync(); - - if (weaponRollList == null) - { - await FollowupAsync("An error occurred fetching curated weapon rolls."); - return; - } - - var rollList = gameMode switch - { - 0 => weaponRollList.PvE, - 1 => weaponRollList.PvP, - _ => null - }; - - if (rollList == null) - { - await FollowupAsync("An error has occurred."); - return; - } - - var requestedRoll = rollList.Where(x => x.WeaponId == weaponId).ToList(); - if (!requestedRoll.Any()) - { - await FollowupAsync("An error has occurred while fetching requested roll."); - return; - } - - var embed = Embeds.MakeBuilder(); - - if (weaponRollList.Authors != null) - { - var rollAuthor = weaponRollList.Authors.FirstOrDefault(x => x.Id == requestedRoll.First().AuthorId); - embed.Author = new EmbedAuthorBuilder - { - Name = rollAuthor?.Name, - IconUrl = rollAuthor?.Image, - Url = rollAuthor?.Url - }; - } - - if (!_bungieClient.Repository.TryGetDestinyDefinition( - requestedRoll.First().WeaponId, - out var weaponDefinition)) - { - await FollowupAsync("Failed to fetch weapon from manifest."); - return; - } - - embed.ThumbnailUrl = weaponDefinition.DisplayProperties.Icon.AbsolutePath; - - var perks = string.Empty; - - for (var i = 0; i < requestedRoll.First().WeaponPerks.Count - 1; i++) - perks += $"{requestedRoll.First().WeaponPerks[i]},"; - - var foundryLink = - $"https://d2foundry.gg/w/{requestedRoll.First().WeaponId}?p={perks.TrimEnd(',')}&m=0&mw={requestedRoll.First().WeaponPerks.Last()}"; - - embed.Description = - $"This is the recommended {Format.Bold(gameMode == 0 ? "PvE" : "PvP")} roll for {Format.Bold(weaponDefinition.DisplayProperties.Name)}.\n" + - $"[Click here]({MiscUtils.GetLightGgLink(requestedRoll.First().WeaponId)}) to view the weapon on Light.GG."; - - embed.AddField("Type", EmoteHelper.StaticEmote(weaponDefinition.EquippingBlock.AmmoType.ToString()) + - EmoteHelper.StaticEmote(weaponDefinition.DefaultDamageTypeEnumValue.ToString()) + - EmoteHelper.GetItemType(weaponDefinition.ItemSubType), true); - embed.AddField("Acquirable", requestedRoll.First().CanDrop, true); - embed.AddField("Source", ReadSource(requestedRoll.First().Source), true); - - for (var i = 0; i < requestedRoll.Count; i++) - { - embed.AddField(requestedRoll.Count != 1 ? $"Recommended roll {i + 1}" : "Why should you pick this roll?", - $"> {requestedRoll[i].Reason}", true); - embed.AddField("Perks", GetPerkList(requestedRoll[i]), true); - embed.AddField("Foundry Link", $"[Click Here]({foundryLink})", true); - } - - await FollowupAsync(embed: embed.Build()); - } - - private static string ReadSource(WeaponSource source) - { - // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault - switch (source) - { - case WeaponSource.XurEternity: - return "Dares Of Eternity"; - case WeaponSource.SeasonalHunt: - case WeaponSource.SeasonalChosen: - case WeaponSource.SeasonalSplicer: - case WeaponSource.SeasonalLost: - case WeaponSource.SeasonalRisen: - case WeaponSource.SeasonalHaunted: - case WeaponSource.SeasonalPlunder: - var split = source.Humanize(LetterCasing.Title).Split(' '); - return $"{split[0]} ({split[1]})"; - default: - return source.Humanize(LetterCasing.Title); - } - } - - private string GetPerkList(Roll requestedRoll) - { - var perkList = new StringBuilder(); - - foreach (var weaponPerk in requestedRoll.WeaponPerks) - { - if (weaponPerk == 0) - { - perkList.Append("*no data*\n"); - continue; - } - - _bungieClient.Repository.TryGetDestinyDefinition(weaponPerk, - out var weaponPerkDefinition); - - if (weaponPerkDefinition.Plug.PlugStyle == PlugUiStyles.Masterwork) - perkList.Append( - EmoteHelper.StaticEmote(weaponPerkDefinition.Plug.PlugCategoryIdentifier.Split('.').Last())); - else - perkList.Append(EmoteHelper.GetEmote(Context.Client, - weaponPerkDefinition.DisplayProperties.Icon.RelativePath, - weaponPerkDefinition.DisplayProperties.Name, weaponPerkDefinition.Hash)); - - perkList.Append(weaponPerkDefinition.DisplayProperties.Name); - - perkList.Append('\n'); - } - - return perkList.ToString(); - } +using System.Text; +using Discord; +using Discord.Interactions; +using DotNetBungieAPI.Models.Destiny; +using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Models; +using Felicity.Util; +using Humanizer; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace Felicity.DiscordCommands.Interactions; + +public class RollFinderCommands : InteractionModuleBase +{ + private readonly IBungieClient _bungieClient; + + public RollFinderCommands(IBungieClient bungieClient) + { + _bungieClient = bungieClient; + } + + [SlashCommand("roll-finder", "Find a recommended roll for a specific weapon from a curated list.")] + public async Task RollFinder( + [Summary("game-mode", "Game mode to suggest rolls for:")] [Choice("PvE", 0)] [Choice("PvP", 1)] + int gameMode, + [Autocomplete(typeof(RollFinderAutocomplete))] [Summary("weapon-name", "Name of the weapon to search for:")] + uint weaponId) + { + await DeferAsync(); + + var weaponRollList = await ProcessRollData.FromJsonAsync(); + + if (weaponRollList == null) + { + await FollowupAsync("An error occurred fetching curated weapon rolls."); + return; + } + + var rollList = gameMode switch + { + 0 => weaponRollList.PvE, + 1 => weaponRollList.PvP, + _ => null + }; + + if (rollList == null) + { + await FollowupAsync("An error has occurred."); + return; + } + + var requestedRoll = rollList.Where(x => x.WeaponId == weaponId).ToList(); + if (!requestedRoll.Any()) + { + await FollowupAsync("An error has occurred while fetching requested roll."); + return; + } + + var embed = Embeds.MakeBuilder(); + + if (weaponRollList.Authors != null) + { + var rollAuthor = weaponRollList.Authors.FirstOrDefault(x => x.Id == requestedRoll.First().AuthorId); + embed.Author = new EmbedAuthorBuilder + { + Name = rollAuthor?.Name, + IconUrl = rollAuthor?.Image, + Url = rollAuthor?.Url + }; + } + + if (!_bungieClient.Repository.TryGetDestinyDefinition( + requestedRoll.First().WeaponId, + out var weaponDefinition)) + { + await FollowupAsync("Failed to fetch weapon from manifest."); + return; + } + + embed.ThumbnailUrl = weaponDefinition.DisplayProperties.Icon.AbsolutePath; + + var perks = string.Empty; + + for (var i = 0; i < requestedRoll.First().WeaponPerks.Count - 1; i++) + perks += $"{requestedRoll.First().WeaponPerks[i]},"; + + var foundryLink = + $"https://d2foundry.gg/w/{requestedRoll.First().WeaponId}?p={perks.TrimEnd(',')}&m=0&mw={requestedRoll.First().WeaponPerks.Last()}"; + + embed.Description = + $"This is the recommended {Format.Bold(gameMode == 0 ? "PvE" : "PvP")} roll for {Format.Bold(weaponDefinition.DisplayProperties.Name)}.\n" + + $"[Click here]({MiscUtils.GetLightGgLink(requestedRoll.First().WeaponId)}) to view the weapon on Light.GG."; + + embed.AddField("Type", EmoteHelper.StaticEmote(weaponDefinition.EquippingBlock.AmmoType.ToString()) + + EmoteHelper.StaticEmote(weaponDefinition.DefaultDamageTypeEnumValue.ToString()) + + EmoteHelper.GetItemType(weaponDefinition.ItemSubType), true); + embed.AddField("Acquirable", requestedRoll.First().CanDrop, true); + embed.AddField("Source", ReadSource(requestedRoll.First().Source), true); + + for (var i = 0; i < requestedRoll.Count; i++) + { + embed.AddField(requestedRoll.Count != 1 ? $"Recommended roll {i + 1}" : "Why should you pick this roll?", + $"> {requestedRoll[i].Reason}", true); + embed.AddField("Perks", GetPerkList(requestedRoll[i]), true); + embed.AddField("Foundry Link", $"[Click Here]({foundryLink})", true); + } + + await FollowupAsync(embed: embed.Build()); + } + + private static string ReadSource(WeaponSource source) + { + // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault + switch (source) + { + case WeaponSource.XurEternity: + return "Dares Of Eternity"; + case WeaponSource.SeasonalHunt: + case WeaponSource.SeasonalChosen: + case WeaponSource.SeasonalSplicer: + case WeaponSource.SeasonalLost: + case WeaponSource.SeasonalRisen: + case WeaponSource.SeasonalHaunted: + case WeaponSource.SeasonalPlunder: + var split = source.Humanize(LetterCasing.Title).Split(' '); + return $"{split[0]} ({split[1]})"; + default: + return source.Humanize(LetterCasing.Title); + } + } + + private string GetPerkList(Roll requestedRoll) + { + var perkList = new StringBuilder(); + + foreach (var weaponPerk in requestedRoll.WeaponPerks) + { + if (weaponPerk == 0) + { + perkList.Append("*no data*\n"); + continue; + } + + _bungieClient.Repository.TryGetDestinyDefinition(weaponPerk, + out var weaponPerkDefinition); + + if (weaponPerkDefinition.Plug.PlugStyle == PlugUiStyles.Masterwork) + perkList.Append( + EmoteHelper.StaticEmote(weaponPerkDefinition.Plug.PlugCategoryIdentifier.Split('.').Last())); + else + perkList.Append(EmoteHelper.GetEmote(Context.Client, + weaponPerkDefinition.DisplayProperties.Icon.RelativePath, + weaponPerkDefinition.DisplayProperties.Name, weaponPerkDefinition.Hash)); + + perkList.Append(weaponPerkDefinition.DisplayProperties.Name); + + perkList.Append('\n'); + } + + return perkList.ToString(); + } } \ No newline at end of file diff --git a/Felicity/DiscordCommands/Interactions/SupportCommands.cs b/Felicity/DiscordCommands/Interactions/SupportCommands.cs index b04699c..07ace0e 100644 --- a/Felicity/DiscordCommands/Interactions/SupportCommands.cs +++ b/Felicity/DiscordCommands/Interactions/SupportCommands.cs @@ -1,33 +1,33 @@ -using Discord; -using Discord.Interactions; -using Felicity.Util; - -// ReSharper disable UnusedType.Global -// ReSharper disable UnusedMember.Global - -namespace Felicity.DiscordCommands.Interactions; - -public class SupportCommands : InteractionModuleBase -{ - [SlashCommand("support", "Get helpful links for the Felicity project.")] - public async Task Support() - { - await DeferAsync(); - - var embed = Embeds.MakeBuilder(); - embed.Title = "Thank you for your interest in Felicity."; - embed.Color = Color.Green; - embed.ThumbnailUrl = BotVariables.Images.FelicitySquare; - embed.Description = Format.Bold("--- Useful links:") + - $"\n<:discord:994211332301791283> [Support Server]({BotVariables.DiscordInvite})" + - "\n<:twitter:994216171110932510> [Twitter](https://twitter.com/devFelicity)" + - "\n🌐 [Website](https://tryfelicity.one)" + - "\n\n" + Format.Bold("--- Contribute to upkeep:") + - "\n• <:kofi:994212063041835098> Donate one-time or monthly on [Ko-Fi](https://ko-fi.com/mooniegz)" + - "\n• <:paypal:994215375141097493> Donate any amount through [PayPal](https://donate.tryfelicity.one)" + - "\n• <:github:994212386204549160> Become a sponsor on [GitHub](https://github.com/sponsors/MoonieGZ)" + - "\n• <:twitch:994214014055895040> Subscribe on [Twitch](https://twitch.tv/subs/MoonieGZ) *(free once per month with Amazon Prime)*"; - - await FollowupAsync(embed: embed.Build()); - } +using Discord; +using Discord.Interactions; +using Felicity.Util; + +// ReSharper disable UnusedType.Global +// ReSharper disable UnusedMember.Global + +namespace Felicity.DiscordCommands.Interactions; + +public class SupportCommands : InteractionModuleBase +{ + [SlashCommand("support", "Get helpful links for the Felicity project.")] + public async Task Support() + { + await DeferAsync(); + + var embed = Embeds.MakeBuilder(); + embed.Title = "Thank you for your interest in Felicity."; + embed.Color = Color.Green; + embed.ThumbnailUrl = BotVariables.Images.FelicitySquare; + embed.Description = Format.Bold("--- Useful links:") + + $"\n<:discord:994211332301791283> [Support Server]({BotVariables.DiscordInvite})" + + "\n<:twitter:994216171110932510> [Twitter](https://twitter.com/devFelicity)" + + "\n🌐 [Website](https://tryfelicity.one)" + + "\n\n" + Format.Bold("--- Contribute to upkeep:") + + "\n• <:kofi:994212063041835098> Donate one-time or monthly on [Ko-Fi](https://ko-fi.com/mooniegz)" + + "\n• <:paypal:994215375141097493> Donate any amount through [PayPal](https://donate.tryfelicity.one)" + + "\n• <:github:994212386204549160> Become a sponsor on [GitHub](https://github.com/sponsors/MoonieGZ)" + + "\n• <:twitch:994214014055895040> Subscribe on [Twitch](https://twitch.tv/subs/MoonieGZ) *(free once per month with Amazon Prime)*"; + + await FollowupAsync(embed: embed.Build()); + } } \ No newline at end of file diff --git a/Felicity/DiscordCommands/Text/EmblemTextCommands.cs b/Felicity/DiscordCommands/Text/EmblemTextCommands.cs index 8d0de9c..552f136 100644 --- a/Felicity/DiscordCommands/Text/EmblemTextCommands.cs +++ b/Felicity/DiscordCommands/Text/EmblemTextCommands.cs @@ -1,76 +1,76 @@ -using System.Text; -using System.Text.Json; -using Discord; -using Discord.Commands; -using DotNetBungieAPI.Models.Destiny; -using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Util; - -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global - -namespace Felicity.DiscordCommands.Text; - -[Preconditions.RequireBotModerator] -public class EmblemTextCommands : ModuleBase -{ - private readonly IBungieClient _client; - - public EmblemTextCommands(IBungieClient client) - { - _client = client; - } - - [Command("storeEmblems")] - public async Task StoreEmblems() - { - var knownEmblems = FetchAllEmblems(); - - await File.WriteAllTextAsync($"Data/emblems/{DateTime.UtcNow:yy-MM-dd}.json", - JsonSerializer.Serialize(knownEmblems)); - - await ReplyAsync($"Saved {knownEmblems.Count} emblems."); - } - - [Command("compareEmblems")] - public async Task CompareEmblems(string originDate) - { - var previousEmblems = - JsonSerializer.Deserialize>(await File.ReadAllTextAsync($"Data/emblems/{originDate}.json")); - var newEmblems = FetchAllEmblems(); - - if (previousEmblems != null) - { - var sb = new StringBuilder(); - - var uniqueEmblems = newEmblems.Except(previousEmblems).ToList(); - foreach (var uniqueEmblem in uniqueEmblems) - if (_client.Repository.TryGetDestinyDefinition(uniqueEmblem, - out var emblemDefinition)) - sb.Append( - $"{emblemDefinition.DisplayProperties.Name}: {emblemDefinition.SecondaryIcon.AbsolutePath}\n"); - - var bytes = new MemoryStream(Encoding.UTF8.GetBytes(sb.ToString())); - await Context.Channel.SendFileAsync(new FileAttachment(bytes, "emblemComparison.txt")); - } - } - - private List FetchAllEmblems() - { - var knownEmblems = new List(); - foreach (var itemDefinition in _client.Repository.GetAll()) - { - if (itemDefinition.ItemType != DestinyItemType.Emblem) - continue; - - if (itemDefinition.Redacted) - continue; - - if (!knownEmblems.Contains(itemDefinition.Hash)) - knownEmblems.Add(itemDefinition.Hash); - } - - return knownEmblems; - } +using System.Text; +using System.Text.Json; +using Discord; +using Discord.Commands; +using DotNetBungieAPI.Models.Destiny; +using DotNetBungieAPI.Models.Destiny.Definitions.InventoryItems; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Util; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace Felicity.DiscordCommands.Text; + +[Preconditions.RequireBotModerator] +public class EmblemTextCommands : ModuleBase +{ + private readonly IBungieClient _client; + + public EmblemTextCommands(IBungieClient client) + { + _client = client; + } + + [Command("storeEmblems")] + public async Task StoreEmblems() + { + var knownEmblems = FetchAllEmblems(); + + await File.WriteAllTextAsync($"Data/emblems/{DateTime.UtcNow:yy-MM-dd}.json", + JsonSerializer.Serialize(knownEmblems)); + + await ReplyAsync($"Saved {knownEmblems.Count} emblems."); + } + + [Command("compareEmblems")] + public async Task CompareEmblems(string originDate) + { + var previousEmblems = + JsonSerializer.Deserialize>(await File.ReadAllTextAsync($"Data/emblems/{originDate}.json")); + var newEmblems = FetchAllEmblems(); + + if (previousEmblems != null) + { + var sb = new StringBuilder(); + + var uniqueEmblems = newEmblems.Except(previousEmblems).ToList(); + foreach (var uniqueEmblem in uniqueEmblems) + if (_client.Repository.TryGetDestinyDefinition(uniqueEmblem, + out var emblemDefinition)) + sb.Append( + $"{emblemDefinition.DisplayProperties.Name}: {emblemDefinition.SecondaryIcon.AbsolutePath}\n"); + + var bytes = new MemoryStream(Encoding.UTF8.GetBytes(sb.ToString())); + await Context.Channel.SendFileAsync(new FileAttachment(bytes, "emblemComparison.txt")); + } + } + + private List FetchAllEmblems() + { + var knownEmblems = new List(); + foreach (var itemDefinition in _client.Repository.GetAll()) + { + if (itemDefinition.ItemType != DestinyItemType.Emblem) + continue; + + if (itemDefinition.Redacted) + continue; + + if (!knownEmblems.Contains(itemDefinition.Hash)) + knownEmblems.Add(itemDefinition.Hash); + } + + return knownEmblems; + } } \ No newline at end of file diff --git a/Felicity/Felicity.csproj b/Felicity/Felicity.csproj index 837826e..f6cacea 100644 --- a/Felicity/Felicity.csproj +++ b/Felicity/Felicity.csproj @@ -1,41 +1,41 @@ - - - - net6.0 - enable - enable - 581e6930-6463-4c70-a3cb-9932d090442e - Linux - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - - + + + + net6.0 + enable + enable + 581e6930-6463-4c70-a3cb-9932d090442e + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/Felicity/Models/Caches/GunsmithCache.cs b/Felicity/Models/Caches/GunsmithCache.cs index 9425ed9..cca967d 100644 --- a/Felicity/Models/Caches/GunsmithCache.cs +++ b/Felicity/Models/Caches/GunsmithCache.cs @@ -1,98 +1,98 @@ -using Discord; -using Discord.WebSocket; -using DotNetBungieAPI.Extensions; -using DotNetBungieAPI.HashReferences; -using DotNetBungieAPI.Models.Destiny; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Util; -using Serilog; - -namespace Felicity.Models.Caches; - -public class GunsmithCache -{ - public DateTime InventoryExpires { get; set; } = DateTime.UtcNow; - public List GunsmithInventory { get; init; } = new(); -} - -public static class ProcessGunsmithData -{ - public static Embed BuildEmbed(GunsmithCache self, BaseSocketClient discordClient) - { - var embed = Embeds.MakeBuilder(); - embed.Title = "Banshee-44"; - embed.ThumbnailUrl = BotVariables.Images.GunsmithVendorLogo; - embed.Description = - "Banshee-44 has lived many lives. As master weaponsmith for the Tower, he supplies Guardians with only the best."; - - var weapons = WeaponHelper.PopulateWeaponPerks(discordClient, self.GunsmithInventory, false); - embed.AddField("Weapons", weapons, true); - - return embed.Build(); - } - - public static async Task FetchInventory(User oauth, IBungieClient bungieClient) - { - /*var path = $"Data/gsCache-{lg}.json"; - - if (File.Exists(path)) - { - gsCache = JsonSerializer.Deserialize(await File.ReadAllTextAsync(path)); - - if (gsCache != null && gsCache.InventoryExpires < DateTime.UtcNow) - File.Delete(path); - else - return gsCache; - }*/ - - var characterIdTask = await bungieClient.ApiAccess.Destiny2.GetProfile(oauth.DestinyMembershipType, - oauth.DestinyMembershipId, new[] - { - DestinyComponentType.Characters - }); - - var vendorData = await bungieClient.ApiAccess.Destiny2.GetVendor(oauth.DestinyMembershipType, - oauth.DestinyMembershipId, characterIdTask.Response.Characters.Data.Keys.First(), - DefinitionHashes.Vendors.Banshee44_672118013, new[] - { - DestinyComponentType.ItemSockets, - DestinyComponentType.VendorCategories, - DestinyComponentType.VendorSales - }, oauth.GetTokenData()); - - if (vendorData.Response.Sales.Data.Keys.Count == 0) - { - Log.Error("Gunsmith inventory lookup failed."); - return null; - } - - var weaponList = new List(); - - foreach (var itemIndex in vendorData.Response.Categories.Data.Categories.ElementAt(2).ItemIndexes) - { - if (!vendorData.Response.Sales.Data[itemIndex].Item.TryGetDefinition(out var itemDefinition)) - continue; - - var weapon = new Weapon - { - Name = itemDefinition!.DisplayProperties.Name, - DestinyItemType = itemDefinition.ItemSubType, - WeaponId = itemDefinition.Hash, - Perks = await WeaponHelper.BuildPerks(bungieClient, ItemTierType.Superior, - vendorData.Response.ItemComponents.Sockets.Data[itemIndex]) - }; - - weaponList.Add(weapon); - } - - var gsCache = new GunsmithCache - { - InventoryExpires = ResetUtils.GetNextDailyReset(), - GunsmithInventory = weaponList - }; - - // await File.WriteAllTextAsync($"Data/gsCache-{lg}.json", JsonSerializer.Serialize(gsCache)); - - return gsCache; - } +using Discord; +using Discord.WebSocket; +using DotNetBungieAPI.Extensions; +using DotNetBungieAPI.HashReferences; +using DotNetBungieAPI.Models.Destiny; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Util; +using Serilog; + +namespace Felicity.Models.Caches; + +public class GunsmithCache +{ + public DateTime InventoryExpires { get; set; } = DateTime.UtcNow; + public List GunsmithInventory { get; init; } = new(); +} + +public static class ProcessGunsmithData +{ + public static Embed BuildEmbed(GunsmithCache self, BaseSocketClient discordClient) + { + var embed = Embeds.MakeBuilder(); + embed.Title = "Banshee-44"; + embed.ThumbnailUrl = BotVariables.Images.GunsmithVendorLogo; + embed.Description = + "Banshee-44 has lived many lives. As master weaponsmith for the Tower, he supplies Guardians with only the best."; + + var weapons = WeaponHelper.PopulateWeaponPerks(discordClient, self.GunsmithInventory, false); + embed.AddField("Weapons", weapons, true); + + return embed.Build(); + } + + public static async Task FetchInventory(User oauth, IBungieClient bungieClient) + { + /*var path = $"Data/gsCache-{lg}.json"; + + if (File.Exists(path)) + { + gsCache = JsonSerializer.Deserialize(await File.ReadAllTextAsync(path)); + + if (gsCache != null && gsCache.InventoryExpires < DateTime.UtcNow) + File.Delete(path); + else + return gsCache; + }*/ + + var characterIdTask = await bungieClient.ApiAccess.Destiny2.GetProfile(oauth.DestinyMembershipType, + oauth.DestinyMembershipId, new[] + { + DestinyComponentType.Characters + }); + + var vendorData = await bungieClient.ApiAccess.Destiny2.GetVendor(oauth.DestinyMembershipType, + oauth.DestinyMembershipId, characterIdTask.Response.Characters.Data.Keys.First(), + DefinitionHashes.Vendors.Banshee44_672118013, new[] + { + DestinyComponentType.ItemSockets, + DestinyComponentType.VendorCategories, + DestinyComponentType.VendorSales + }, oauth.GetTokenData()); + + if (vendorData.Response.Sales.Data.Keys.Count == 0) + { + Log.Error("Gunsmith inventory lookup failed."); + return null; + } + + var weaponList = new List(); + + foreach (var itemIndex in vendorData.Response.Categories.Data.Categories.ElementAt(2).ItemIndexes) + { + if (!vendorData.Response.Sales.Data[itemIndex].Item.TryGetDefinition(out var itemDefinition)) + continue; + + var weapon = new Weapon + { + Name = itemDefinition!.DisplayProperties.Name, + DestinyItemType = itemDefinition.ItemSubType, + WeaponId = itemDefinition.Hash, + Perks = await WeaponHelper.BuildPerks(bungieClient, ItemTierType.Superior, + vendorData.Response.ItemComponents.Sockets.Data[itemIndex]) + }; + + weaponList.Add(weapon); + } + + var gsCache = new GunsmithCache + { + InventoryExpires = ResetUtils.GetNextDailyReset(), + GunsmithInventory = weaponList + }; + + // await File.WriteAllTextAsync($"Data/gsCache-{lg}.json", JsonSerializer.Serialize(gsCache)); + + return gsCache; + } } \ No newline at end of file diff --git a/Felicity/Models/Checkpoints.cs b/Felicity/Models/Checkpoints.cs index c2d4f3f..c63c465 100644 --- a/Felicity/Models/Checkpoints.cs +++ b/Felicity/Models/Checkpoints.cs @@ -1,73 +1,73 @@ -using System.Text.Json.Serialization; -using Felicity.Util; - -// ReSharper disable UnusedAutoPropertyAccessor.Global -// ReSharper disable ClassNeverInstantiated.Global -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global -#pragma warning disable CS8618 - -namespace Felicity.Models; - -public class CheckpointParser -{ - public static async Task FetchAsync() - { - try - { - return await HttpClientInstance.Instance.GetFromJsonAsync( - "https://d2cp.io/platform/checkpoints?v=2"); - } - catch - { - // ignored - } - - return null; - } -} - -public class Checkpoints -{ - [JsonPropertyName("official")] public Official[]? Official { get; set; } - - [JsonPropertyName("community")] public object Community { get; set; } - - [JsonPropertyName("alert")] public Alert Alert { get; set; } -} - -public class Alert -{ - [JsonPropertyName("alertActive")] public bool AlertActive { get; set; } - - [JsonPropertyName("alertText")] public string AlertText { get; set; } -} - -public class Official -{ - [JsonPropertyName("name")] public string Name { get; set; } - - [JsonPropertyName("activity")] public string Activity { get; set; } - - [JsonPropertyName("activityHash")] public long ActivityHash { get; set; } - - [JsonPropertyName("encounter")] public string Encounter { get; set; } - - [JsonPropertyName("players")] public int Players { get; set; } - - [JsonPropertyName("maxPlayers")] public int MaxPlayers { get; set; } - - [JsonPropertyName("difficultyTier")] public Difficulty DifficultyTier { get; set; } - - [JsonPropertyName("imgURL")] public string ImgUrl { get; set; } - - [JsonPropertyName("iconURL")] public string IconUrl { get; set; } - - [JsonPropertyName("displayOrder")] public int DisplayOrder { get; set; } -} - -public enum Difficulty -{ - Normal = 2, - Master = 3 +using System.Text.Json.Serialization; +using Felicity.Util; + +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global +#pragma warning disable CS8618 + +namespace Felicity.Models; + +public class CheckpointParser +{ + public static async Task FetchAsync() + { + try + { + return await HttpClientInstance.Instance.GetFromJsonAsync( + "https://d2cp.io/platform/checkpoints?v=2"); + } + catch + { + // ignored + } + + return null; + } +} + +public class Checkpoints +{ + [JsonPropertyName("official")] public Official[]? Official { get; set; } + + [JsonPropertyName("community")] public object Community { get; set; } + + [JsonPropertyName("alert")] public Alert Alert { get; set; } +} + +public class Alert +{ + [JsonPropertyName("alertActive")] public bool AlertActive { get; set; } + + [JsonPropertyName("alertText")] public string AlertText { get; set; } +} + +public class Official +{ + [JsonPropertyName("name")] public string Name { get; set; } + + [JsonPropertyName("activity")] public string Activity { get; set; } + + [JsonPropertyName("activityHash")] public long ActivityHash { get; set; } + + [JsonPropertyName("encounter")] public string Encounter { get; set; } + + [JsonPropertyName("players")] public int Players { get; set; } + + [JsonPropertyName("maxPlayers")] public int MaxPlayers { get; set; } + + [JsonPropertyName("difficultyTier")] public Difficulty DifficultyTier { get; set; } + + [JsonPropertyName("imgURL")] public string ImgUrl { get; set; } + + [JsonPropertyName("iconURL")] public string IconUrl { get; set; } + + [JsonPropertyName("displayOrder")] public int DisplayOrder { get; set; } +} + +public enum Difficulty +{ + Normal = 2, + Master = 3 } \ No newline at end of file diff --git a/Felicity/Models/Clarity.cs b/Felicity/Models/Clarity.cs index 05323df..d482aeb 100644 --- a/Felicity/Models/Clarity.cs +++ b/Felicity/Models/Clarity.cs @@ -1,300 +1,300 @@ -using System.Globalization; -using Felicity.Util; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -// ReSharper disable ClassNeverInstantiated.Global - -namespace Felicity.Models; - -public class Clarity -{ - [JsonProperty("hash")] public long Hash { get; set; } - - [JsonProperty("name")] public string? Name { get; set; } - - [JsonProperty("lastUpdate")] public long LastUpdate { get; set; } - - [JsonProperty("updatedBy")] public string? UpdatedBy { get; set; } - - [JsonProperty("type")] public TypeEnum Type { get; set; } - - [JsonProperty("description")] public string? Description { get; set; } - - [JsonProperty("stats", NullValueHandling = NullValueHandling.Ignore)] - public Stats? Stats { get; set; } - - [JsonProperty("itemHash", NullValueHandling = NullValueHandling.Ignore)] - public long? ItemHash { get; set; } - - [JsonProperty("itemName", NullValueHandling = NullValueHandling.Ignore)] - public string? ItemName { get; set; } - - [JsonProperty("investmentStatOnly", NullValueHandling = NullValueHandling.Ignore)] - public bool? InvestmentStatOnly { get; set; } -} - -public class Stats -{ - [JsonProperty("damage", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Damage { get; set; } - - [JsonProperty("range", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Range { get; set; } - - [JsonProperty("handling", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Handling { get; set; } - - [JsonProperty("reload", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Reload { get; set; } - - [JsonProperty("stability", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Stability { get; set; } - - [JsonProperty("aimAssist", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? AimAssist { get; set; } - - [JsonProperty("chargeDraw", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? ChargeDraw { get; set; } - - [JsonProperty("chargeDrawTime", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? ChargeDrawTime { get; set; } - - [JsonProperty("draw", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Draw { get; set; } - - [JsonProperty("zoom", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Zoom { get; set; } - - [JsonProperty("stow", NullValueHandling = NullValueHandling.Ignore)] - public Stat[]? Stow { get; set; } -} - -public class StatType -{ - [JsonProperty("stat")] public long[]? Stat { get; set; } - - [JsonProperty("multiplier", NullValueHandling = NullValueHandling.Ignore)] - public double[]? Multiplier { get; set; } -} - -public class Stat -{ - [JsonProperty("active", NullValueHandling = NullValueHandling.Ignore)] - public StatType? Active { get; set; } - - [JsonProperty("passive", NullValueHandling = NullValueHandling.Ignore)] - public StatType? Passive { get; set; } -} - -public enum TypeEnum -{ - ArmorModActivity, - ArmorModGeneral, - ArmorPerkExotic, - SubclassClass, - SubclassFragment, - SubclassGrenade, - SubclassMelee, - SubclassMovement, - SubclassSuper, - TypeWeaponCatalystExotic, - TypeWeaponFrame, - TypeWeaponFrameExotic, - TypeWeaponMod, - TypeWeaponPerkEnhanced, - WeaponCatalystExotic, - WeaponFrame, - WeaponFrameExotic, - WeaponMod, - WeaponOriginTrait, - WeaponPerk, - WeaponPerkEnhanced, - WeaponPerkExotic -} - -public static class ClarityParser -{ - private static Dictionary? _clarityDb; - - public static string ToJson(this Dictionary self) - { - return JsonConvert.SerializeObject(self, Converter.Settings); - } - - public static async Task?> Fetch() - { - if (_clarityDb != null) - return _clarityDb; - - using var httpClient = new HttpClient(); - var json = await httpClient.GetStringAsync( - "https://raw.githubusercontent.com/Database-Clarity/Live-Clarity-Database/live/descriptions/crayon.json"); - - _clarityDb = JsonConvert.DeserializeObject>(json, Converter.Settings); - - return _clarityDb; - } - - public static string ClarityClean(this string inputString) - { - var outputString = inputString - .Replace("export description (\n", "") - .Replace("[this sheet ](https://d2clarity.page.link/combatantundefined", - "[this sheet](https://d2clarity.page.link/combatant)") - .Replace("->1", "-> 1") - .Replace("\r", "") - .Replace("**", "") - .Replace("<:primary:968793055677251604>", EmoteHelper.StaticEmote("primary")) - .Replace("<:special:968793055631114330>", EmoteHelper.StaticEmote("special")) - .Replace("<:heavy:968793055652106320>", EmoteHelper.StaticEmote("heavy")) - .Replace("<:stasis:915198000727461909>", EmoteHelper.StaticEmote("stasis")) - .Replace("<:arc:720178925317128243>", EmoteHelper.StaticEmote("arc")) - .Replace("<:solar:720178909361995786>", EmoteHelper.StaticEmote("solar")) - .Replace("<:void:720178940240461864>", EmoteHelper.StaticEmote("void")) - .Replace("<:pve:922884406073507930>", EmoteHelper.StaticEmote("pve")) - .Replace("<:pvp:922884468275019856>", EmoteHelper.StaticEmote("pvp")); - - return outputString; - } -} - -internal static class Converter -{ - public static readonly JsonSerializerSettings? Settings = new() - { - MetadataPropertyHandling = MetadataPropertyHandling.Ignore, - DateParseHandling = DateParseHandling.None, - Converters = - { - TypeEnumConverter.Singleton, - new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } - } - }; -} - -internal class TypeEnumConverter : JsonConverter -{ - public static readonly TypeEnumConverter Singleton = new(); - - public override bool CanConvert(Type t) - { - return t == typeof(TypeEnum) || t == typeof(TypeEnum?); - } - - public override object? ReadJson(JsonReader reader, Type t, object? existingValue, JsonSerializer serializer) - { - if (reader.TokenType == JsonToken.Null) - return null; - - var value = serializer.Deserialize(reader); - return value switch - { - "Armor Mod Activity" => TypeEnum.ArmorModActivity, - "Armor Mod General" => TypeEnum.ArmorModGeneral, - "Armor Perk Exotic" => TypeEnum.ArmorPerkExotic, - "Subclass Class" => TypeEnum.SubclassClass, - "Subclass Fragment" => TypeEnum.SubclassFragment, - "Subclass Grenade" => TypeEnum.SubclassGrenade, - "Subclass Melee" => TypeEnum.SubclassMelee, - "Subclass Movement" => TypeEnum.SubclassMovement, - "Subclass Super" => TypeEnum.SubclassSuper, - "Weapon Catalyst Exotic" => TypeEnum.WeaponCatalystExotic, - "Weapon Frame" => TypeEnum.WeaponFrame, - "Weapon Frame Exotic" => TypeEnum.WeaponFrameExotic, - "Weapon Mod" => TypeEnum.WeaponMod, - "Weapon Origin Trait" => TypeEnum.WeaponOriginTrait, - "Weapon Perk" => TypeEnum.WeaponPerk, - "Weapon Perk Enhanced" => TypeEnum.WeaponPerkEnhanced, - "Weapon Perk Exotic" => TypeEnum.WeaponPerkExotic, - "weaponCatalystExotic" => TypeEnum.TypeWeaponCatalystExotic, - "weaponFrame" => TypeEnum.TypeWeaponFrame, - "weaponFrameExotic" => TypeEnum.TypeWeaponFrameExotic, - "weaponMod" => TypeEnum.TypeWeaponMod, - "weaponPerkEnhanced" => TypeEnum.TypeWeaponPerkEnhanced, - _ => throw new Exception("Cannot un-marshal type TypeEnum") - }; - } - - public override void WriteJson(JsonWriter writer, object? untypedValue, JsonSerializer serializer) - { - if (untypedValue == null) - { - serializer.Serialize(writer, null); - return; - } - - var value = (TypeEnum)untypedValue; - switch (value) - { - case TypeEnum.ArmorModActivity: - serializer.Serialize(writer, "Armor Mod Activity"); - return; - case TypeEnum.ArmorModGeneral: - serializer.Serialize(writer, "Armor Mod General"); - return; - case TypeEnum.ArmorPerkExotic: - serializer.Serialize(writer, "Armor Perk Exotic"); - return; - case TypeEnum.SubclassClass: - serializer.Serialize(writer, "Subclass Class"); - return; - case TypeEnum.SubclassFragment: - serializer.Serialize(writer, "Subclass Fragment"); - return; - case TypeEnum.SubclassGrenade: - serializer.Serialize(writer, "Subclass Grenade"); - return; - case TypeEnum.SubclassMelee: - serializer.Serialize(writer, "Subclass Melee"); - return; - case TypeEnum.SubclassMovement: - serializer.Serialize(writer, "Subclass Movement"); - return; - case TypeEnum.SubclassSuper: - serializer.Serialize(writer, "Subclass Super"); - return; - case TypeEnum.WeaponCatalystExotic: - serializer.Serialize(writer, "Weapon Catalyst Exotic"); - return; - case TypeEnum.WeaponFrame: - serializer.Serialize(writer, "Weapon Frame"); - return; - case TypeEnum.WeaponFrameExotic: - serializer.Serialize(writer, "Weapon Frame Exotic"); - return; - case TypeEnum.WeaponMod: - serializer.Serialize(writer, "Weapon Mod"); - return; - case TypeEnum.WeaponOriginTrait: - serializer.Serialize(writer, "Weapon Origin Trait"); - return; - case TypeEnum.WeaponPerk: - serializer.Serialize(writer, "Weapon Perk"); - return; - case TypeEnum.WeaponPerkEnhanced: - serializer.Serialize(writer, "Weapon Perk Enhanced"); - return; - case TypeEnum.WeaponPerkExotic: - serializer.Serialize(writer, "Weapon Perk Exotic"); - return; - case TypeEnum.TypeWeaponCatalystExotic: - serializer.Serialize(writer, "weaponCatalystExotic"); - return; - case TypeEnum.TypeWeaponFrame: - serializer.Serialize(writer, "weaponFrame"); - return; - case TypeEnum.TypeWeaponFrameExotic: - serializer.Serialize(writer, "weaponFrameExotic"); - return; - case TypeEnum.TypeWeaponMod: - serializer.Serialize(writer, "weaponMod"); - return; - case TypeEnum.TypeWeaponPerkEnhanced: - serializer.Serialize(writer, "weaponPerkEnhanced"); - return; - default: - throw new Exception("Cannot marshal type TypeEnum"); - } - } +using System.Globalization; +using Felicity.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +// ReSharper disable ClassNeverInstantiated.Global + +namespace Felicity.Models; + +public class Clarity +{ + [JsonProperty("hash")] public long Hash { get; set; } + + [JsonProperty("name")] public string? Name { get; set; } + + [JsonProperty("lastUpdate")] public long LastUpdate { get; set; } + + [JsonProperty("updatedBy")] public string? UpdatedBy { get; set; } + + [JsonProperty("type")] public TypeEnum Type { get; set; } + + [JsonProperty("description")] public string? Description { get; set; } + + [JsonProperty("stats", NullValueHandling = NullValueHandling.Ignore)] + public Stats? Stats { get; set; } + + [JsonProperty("itemHash", NullValueHandling = NullValueHandling.Ignore)] + public long? ItemHash { get; set; } + + [JsonProperty("itemName", NullValueHandling = NullValueHandling.Ignore)] + public string? ItemName { get; set; } + + [JsonProperty("investmentStatOnly", NullValueHandling = NullValueHandling.Ignore)] + public bool? InvestmentStatOnly { get; set; } +} + +public class Stats +{ + [JsonProperty("damage", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Damage { get; set; } + + [JsonProperty("range", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Range { get; set; } + + [JsonProperty("handling", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Handling { get; set; } + + [JsonProperty("reload", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Reload { get; set; } + + [JsonProperty("stability", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Stability { get; set; } + + [JsonProperty("aimAssist", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? AimAssist { get; set; } + + [JsonProperty("chargeDraw", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? ChargeDraw { get; set; } + + [JsonProperty("chargeDrawTime", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? ChargeDrawTime { get; set; } + + [JsonProperty("draw", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Draw { get; set; } + + [JsonProperty("zoom", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Zoom { get; set; } + + [JsonProperty("stow", NullValueHandling = NullValueHandling.Ignore)] + public Stat[]? Stow { get; set; } +} + +public class StatType +{ + [JsonProperty("stat")] public long[]? Stat { get; set; } + + [JsonProperty("multiplier", NullValueHandling = NullValueHandling.Ignore)] + public double[]? Multiplier { get; set; } +} + +public class Stat +{ + [JsonProperty("active", NullValueHandling = NullValueHandling.Ignore)] + public StatType? Active { get; set; } + + [JsonProperty("passive", NullValueHandling = NullValueHandling.Ignore)] + public StatType? Passive { get; set; } +} + +public enum TypeEnum +{ + ArmorModActivity, + ArmorModGeneral, + ArmorPerkExotic, + SubclassClass, + SubclassFragment, + SubclassGrenade, + SubclassMelee, + SubclassMovement, + SubclassSuper, + TypeWeaponCatalystExotic, + TypeWeaponFrame, + TypeWeaponFrameExotic, + TypeWeaponMod, + TypeWeaponPerkEnhanced, + WeaponCatalystExotic, + WeaponFrame, + WeaponFrameExotic, + WeaponMod, + WeaponOriginTrait, + WeaponPerk, + WeaponPerkEnhanced, + WeaponPerkExotic +} + +public static class ClarityParser +{ + private static Dictionary? _clarityDb; + + public static string ToJson(this Dictionary self) + { + return JsonConvert.SerializeObject(self, Converter.Settings); + } + + public static async Task?> Fetch() + { + if (_clarityDb != null) + return _clarityDb; + + using var httpClient = new HttpClient(); + var json = await httpClient.GetStringAsync( + "https://raw.githubusercontent.com/Database-Clarity/Live-Clarity-Database/live/descriptions/crayon.json"); + + _clarityDb = JsonConvert.DeserializeObject>(json, Converter.Settings); + + return _clarityDb; + } + + public static string ClarityClean(this string inputString) + { + var outputString = inputString + .Replace("export description (\n", "") + .Replace("[this sheet ](https://d2clarity.page.link/combatantundefined", + "[this sheet](https://d2clarity.page.link/combatant)") + .Replace("->1", "-> 1") + .Replace("\r", "") + .Replace("**", "") + .Replace("<:primary:968793055677251604>", EmoteHelper.StaticEmote("primary")) + .Replace("<:special:968793055631114330>", EmoteHelper.StaticEmote("special")) + .Replace("<:heavy:968793055652106320>", EmoteHelper.StaticEmote("heavy")) + .Replace("<:stasis:915198000727461909>", EmoteHelper.StaticEmote("stasis")) + .Replace("<:arc:720178925317128243>", EmoteHelper.StaticEmote("arc")) + .Replace("<:solar:720178909361995786>", EmoteHelper.StaticEmote("solar")) + .Replace("<:void:720178940240461864>", EmoteHelper.StaticEmote("void")) + .Replace("<:pve:922884406073507930>", EmoteHelper.StaticEmote("pve")) + .Replace("<:pvp:922884468275019856>", EmoteHelper.StaticEmote("pvp")); + + return outputString; + } +} + +internal static class Converter +{ + public static readonly JsonSerializerSettings? Settings = new() + { + MetadataPropertyHandling = MetadataPropertyHandling.Ignore, + DateParseHandling = DateParseHandling.None, + Converters = + { + TypeEnumConverter.Singleton, + new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } + } + }; +} + +internal class TypeEnumConverter : JsonConverter +{ + public static readonly TypeEnumConverter Singleton = new(); + + public override bool CanConvert(Type t) + { + return t == typeof(TypeEnum) || t == typeof(TypeEnum?); + } + + public override object? ReadJson(JsonReader reader, Type t, object? existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + + var value = serializer.Deserialize(reader); + return value switch + { + "Armor Mod Activity" => TypeEnum.ArmorModActivity, + "Armor Mod General" => TypeEnum.ArmorModGeneral, + "Armor Perk Exotic" => TypeEnum.ArmorPerkExotic, + "Subclass Class" => TypeEnum.SubclassClass, + "Subclass Fragment" => TypeEnum.SubclassFragment, + "Subclass Grenade" => TypeEnum.SubclassGrenade, + "Subclass Melee" => TypeEnum.SubclassMelee, + "Subclass Movement" => TypeEnum.SubclassMovement, + "Subclass Super" => TypeEnum.SubclassSuper, + "Weapon Catalyst Exotic" => TypeEnum.WeaponCatalystExotic, + "Weapon Frame" => TypeEnum.WeaponFrame, + "Weapon Frame Exotic" => TypeEnum.WeaponFrameExotic, + "Weapon Mod" => TypeEnum.WeaponMod, + "Weapon Origin Trait" => TypeEnum.WeaponOriginTrait, + "Weapon Perk" => TypeEnum.WeaponPerk, + "Weapon Perk Enhanced" => TypeEnum.WeaponPerkEnhanced, + "Weapon Perk Exotic" => TypeEnum.WeaponPerkExotic, + "weaponCatalystExotic" => TypeEnum.TypeWeaponCatalystExotic, + "weaponFrame" => TypeEnum.TypeWeaponFrame, + "weaponFrameExotic" => TypeEnum.TypeWeaponFrameExotic, + "weaponMod" => TypeEnum.TypeWeaponMod, + "weaponPerkEnhanced" => TypeEnum.TypeWeaponPerkEnhanced, + _ => throw new Exception("Cannot un-marshal type TypeEnum") + }; + } + + public override void WriteJson(JsonWriter writer, object? untypedValue, JsonSerializer serializer) + { + if (untypedValue == null) + { + serializer.Serialize(writer, null); + return; + } + + var value = (TypeEnum)untypedValue; + switch (value) + { + case TypeEnum.ArmorModActivity: + serializer.Serialize(writer, "Armor Mod Activity"); + return; + case TypeEnum.ArmorModGeneral: + serializer.Serialize(writer, "Armor Mod General"); + return; + case TypeEnum.ArmorPerkExotic: + serializer.Serialize(writer, "Armor Perk Exotic"); + return; + case TypeEnum.SubclassClass: + serializer.Serialize(writer, "Subclass Class"); + return; + case TypeEnum.SubclassFragment: + serializer.Serialize(writer, "Subclass Fragment"); + return; + case TypeEnum.SubclassGrenade: + serializer.Serialize(writer, "Subclass Grenade"); + return; + case TypeEnum.SubclassMelee: + serializer.Serialize(writer, "Subclass Melee"); + return; + case TypeEnum.SubclassMovement: + serializer.Serialize(writer, "Subclass Movement"); + return; + case TypeEnum.SubclassSuper: + serializer.Serialize(writer, "Subclass Super"); + return; + case TypeEnum.WeaponCatalystExotic: + serializer.Serialize(writer, "Weapon Catalyst Exotic"); + return; + case TypeEnum.WeaponFrame: + serializer.Serialize(writer, "Weapon Frame"); + return; + case TypeEnum.WeaponFrameExotic: + serializer.Serialize(writer, "Weapon Frame Exotic"); + return; + case TypeEnum.WeaponMod: + serializer.Serialize(writer, "Weapon Mod"); + return; + case TypeEnum.WeaponOriginTrait: + serializer.Serialize(writer, "Weapon Origin Trait"); + return; + case TypeEnum.WeaponPerk: + serializer.Serialize(writer, "Weapon Perk"); + return; + case TypeEnum.WeaponPerkEnhanced: + serializer.Serialize(writer, "Weapon Perk Enhanced"); + return; + case TypeEnum.WeaponPerkExotic: + serializer.Serialize(writer, "Weapon Perk Exotic"); + return; + case TypeEnum.TypeWeaponCatalystExotic: + serializer.Serialize(writer, "weaponCatalystExotic"); + return; + case TypeEnum.TypeWeaponFrame: + serializer.Serialize(writer, "weaponFrame"); + return; + case TypeEnum.TypeWeaponFrameExotic: + serializer.Serialize(writer, "weaponFrameExotic"); + return; + case TypeEnum.TypeWeaponMod: + serializer.Serialize(writer, "weaponMod"); + return; + case TypeEnum.TypeWeaponPerkEnhanced: + serializer.Serialize(writer, "weaponPerkEnhanced"); + return; + default: + throw new Exception("Cannot marshal type TypeEnum"); + } + } } \ No newline at end of file diff --git a/Felicity/Models/CommandsInfo/CommandInfo.cs b/Felicity/Models/CommandsInfo/CommandInfo.cs index f2953d0..54cf787 100644 --- a/Felicity/Models/CommandsInfo/CommandInfo.cs +++ b/Felicity/Models/CommandsInfo/CommandInfo.cs @@ -1,21 +1,21 @@ -using System.Diagnostics; - -// ReSharper disable MemberCanBePrivate.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global - -namespace Felicity.Models.CommandsInfo; - -[DebuggerDisplay("{CommandPath}, Parameters count = {ParametersInfo.Count}")] -public class CommandInfo -{ - public CommandInfo(string path, string desc) - { - CommandPath = path; - CommandDescription = desc; - ParametersInfo = new List(); - } - - public string CommandPath { get; } - public string CommandDescription { get; } - public List ParametersInfo { get; } +using System.Diagnostics; + +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global + +namespace Felicity.Models.CommandsInfo; + +[DebuggerDisplay("{CommandPath}, Parameters count = {ParametersInfo.Count}")] +public class CommandInfo +{ + public CommandInfo(string path, string desc) + { + CommandPath = path; + CommandDescription = desc; + ParametersInfo = new List(); + } + + public string CommandPath { get; } + public string CommandDescription { get; } + public List ParametersInfo { get; } } \ No newline at end of file diff --git a/Felicity/Models/CommandsInfo/CommandParameterInfo.cs b/Felicity/Models/CommandsInfo/CommandParameterInfo.cs index ec18f4e..bc850f9 100644 --- a/Felicity/Models/CommandsInfo/CommandParameterInfo.cs +++ b/Felicity/Models/CommandsInfo/CommandParameterInfo.cs @@ -1,18 +1,18 @@ -using System.Diagnostics; - -// ReSharper disable UnusedAutoPropertyAccessor.Global -// ReSharper disable UnusedMember.Global -#pragma warning disable CS8618 - -namespace Felicity.Models.CommandsInfo; - -[DebuggerDisplay("{Name}")] -public class CommandParameterInfo -{ - public string Name { get; set; } - public string Description { get; set; } - public bool IsOptional { get; set; } - public object DefaultValue { get; set; } - public bool IsAutocomplete { get; set; } - public bool IsSelect { get; set; } +using System.Diagnostics; + +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable UnusedMember.Global +#pragma warning disable CS8618 + +namespace Felicity.Models.CommandsInfo; + +[DebuggerDisplay("{Name}")] +public class CommandParameterInfo +{ + public string Name { get; set; } + public string Description { get; set; } + public bool IsOptional { get; set; } + public object DefaultValue { get; set; } + public bool IsAutocomplete { get; set; } + public bool IsSelect { get; set; } } \ No newline at end of file diff --git a/Felicity/Models/Metric.cs b/Felicity/Models/Metric.cs index f3d38af..e991664 100644 --- a/Felicity/Models/Metric.cs +++ b/Felicity/Models/Metric.cs @@ -1,32 +1,32 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; - -namespace Felicity.Models; - -public class Metric -{ - [Key] public int Id { get; set; } - public int TimeStamp { get; set; } - public string Author { get; set; } = string.Empty; - public string Name { get; set; } = string.Empty; -} - -public class MetricDb : DbContext -{ - private readonly string? _connectionString; - - public MetricDb(IConfiguration configuration) - { - _connectionString = configuration.GetConnectionString("MySQLDb"); - } - - // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global - public DbSet Metrics { get; set; } = null!; - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - var serverVersion = new MariaDbServerVersion(new Version(10, 2, 21)); - if (_connectionString != null) - optionsBuilder.UseMySql(_connectionString, serverVersion, builder => builder.EnableRetryOnFailure()); - } +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; + +namespace Felicity.Models; + +public class Metric +{ + [Key] public int Id { get; set; } + public int TimeStamp { get; set; } + public string Author { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; +} + +public class MetricDb : DbContext +{ + private readonly string? _connectionString; + + public MetricDb(IConfiguration configuration) + { + _connectionString = configuration.GetConnectionString("MySQLDb"); + } + + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global + public DbSet Metrics { get; set; } = null!; + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + var serverVersion = new MariaDbServerVersion(new Version(10, 2, 21)); + if (_connectionString != null) + optionsBuilder.UseMySql(_connectionString, serverVersion, builder => builder.EnableRetryOnFailure()); + } } \ No newline at end of file diff --git a/Felicity/Models/RecommendedRolls.cs b/Felicity/Models/RecommendedRolls.cs index d8def2f..6f67255 100644 --- a/Felicity/Models/RecommendedRolls.cs +++ b/Felicity/Models/RecommendedRolls.cs @@ -1,127 +1,127 @@ -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable ClassNeverInstantiated.Global -// ReSharper disable CollectionNeverQueried.Global -// ReSharper disable PropertyCanBeMadeInitOnly.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global -// ReSharper disable UnusedMember.Global - -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Felicity.Models; - -public partial class NewWeaponRoll -{ - [JsonPropertyName("weaponRolls")] public List WeaponRolls { get; set; } -} - -public class WeaponRoll -{ - [JsonPropertyName("weaponHash")] public uint WeaponHash { get; set; } - - [JsonPropertyName("authorId")] public int AuthorId { get; set; } - - [JsonPropertyName("source")] public int Source { get; set; } - - [JsonPropertyName("notes")] public string? Notes { get; set; } - - [JsonPropertyName("perks")] public List Perks { get; set; } - - [JsonPropertyName("canDrop")] public bool CanDrop { get; set; } -} - -public partial class NewWeaponRoll -{ - public static NewWeaponRoll FromJson(string json) - { - return JsonSerializer.Deserialize(json)!; - } - - public static string ToJson(NewWeaponRoll self) - { - return JsonSerializer.Serialize(self); - } -} - -public class RecommendedRolls -{ - public List? Authors { get; set; } - public List? PvE { get; set; } - public List? PvP { get; set; } -} - -public class Roll -{ - public int AuthorId { get; set; } - public bool CanDrop { get; set; } - public WeaponSource Source { get; set; } - public string? Reason { get; set; } - public string? WeaponName { get; set; } - public uint WeaponId { get; set; } - public List WeaponPerks { get; set; } = new(); -} - -public class Author -{ - public int Id { get; set; } - public string? Name { get; set; } - public string? Image { get; set; } - public string? Url { get; set; } -} - -public enum WeaponSource -{ - WorldDrop, - LastWish, - GardenOfSalvation, - DeepStoneCrypt, - VaultOfGlass, - VowOfTheDisciple, - GrandmasterNightfall, - ShatteredThrone, - PitOfHeresy, - Prophecy, - GraspOfAvarice, - Duality, - TrialsOfOsiris, - Strikes, - IronBanner, - Crucible, - Gambit, - Moon, - Europa, - XurEternity, - ThroneWorld, - Leviathan, - Event, - KingsFall, - Lightfall, - RootOfNightmares, - GhostsOfTheDeep, - CrotasEnd, - SeasonalHunt = 112, - SeasonalChosen = 113, - SeasonalSplicer = 114, - SeasonalLost = 115, - SeasonalRisen = 116, - SeasonalHaunted = 117, - SeasonalPlunder = 118, - SeasonalSeraph = 119, - SeasonalDefiance = 120, - SeasonalDeep = 121 -} - -public static class ProcessRollData -{ - private const string JsonFile = "Data/weaponRolls.json"; - - public static async Task FromJsonAsync() - { - if (!File.Exists(JsonFile)) - return null; - - await using var stream = File.OpenRead(JsonFile); - return await JsonSerializer.DeserializeAsync(stream); - } +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable CollectionNeverQueried.Global +// ReSharper disable PropertyCanBeMadeInitOnly.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global +// ReSharper disable UnusedMember.Global + +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Felicity.Models; + +public partial class NewWeaponRoll +{ + [JsonPropertyName("weaponRolls")] public List WeaponRolls { get; set; } +} + +public class WeaponRoll +{ + [JsonPropertyName("weaponHash")] public uint WeaponHash { get; set; } + + [JsonPropertyName("authorId")] public int AuthorId { get; set; } + + [JsonPropertyName("source")] public int Source { get; set; } + + [JsonPropertyName("notes")] public string? Notes { get; set; } + + [JsonPropertyName("perks")] public List Perks { get; set; } + + [JsonPropertyName("canDrop")] public bool CanDrop { get; set; } +} + +public partial class NewWeaponRoll +{ + public static NewWeaponRoll FromJson(string json) + { + return JsonSerializer.Deserialize(json)!; + } + + public static string ToJson(NewWeaponRoll self) + { + return JsonSerializer.Serialize(self); + } +} + +public class RecommendedRolls +{ + public List? Authors { get; set; } + public List? PvE { get; set; } + public List? PvP { get; set; } +} + +public class Roll +{ + public int AuthorId { get; set; } + public bool CanDrop { get; set; } + public WeaponSource Source { get; set; } + public string? Reason { get; set; } + public string? WeaponName { get; set; } + public uint WeaponId { get; set; } + public List WeaponPerks { get; set; } = new(); +} + +public class Author +{ + public int Id { get; set; } + public string? Name { get; set; } + public string? Image { get; set; } + public string? Url { get; set; } +} + +public enum WeaponSource +{ + WorldDrop, + LastWish, + GardenOfSalvation, + DeepStoneCrypt, + VaultOfGlass, + VowOfTheDisciple, + GrandmasterNightfall, + ShatteredThrone, + PitOfHeresy, + Prophecy, + GraspOfAvarice, + Duality, + TrialsOfOsiris, + Strikes, + IronBanner, + Crucible, + Gambit, + Moon, + Europa, + XurEternity, + ThroneWorld, + Leviathan, + Event, + KingsFall, + Lightfall, + RootOfNightmares, + GhostsOfTheDeep, + CrotasEnd, + SeasonalHunt = 112, + SeasonalChosen = 113, + SeasonalSplicer = 114, + SeasonalLost = 115, + SeasonalRisen = 116, + SeasonalHaunted = 117, + SeasonalPlunder = 118, + SeasonalSeraph = 119, + SeasonalDefiance = 120, + SeasonalDeep = 121 +} + +public static class ProcessRollData +{ + private const string JsonFile = "Data/weaponRolls.json"; + + public static async Task FromJsonAsync() + { + if (!File.Exists(JsonFile)) + return null; + + await using var stream = File.OpenRead(JsonFile); + return await JsonSerializer.DeserializeAsync(stream); + } } \ No newline at end of file diff --git a/Felicity/Services/Hosted/CommandsInfoService.cs b/Felicity/Services/Hosted/CommandsInfoService.cs index 2aa9a58..17cfe5f 100644 --- a/Felicity/Services/Hosted/CommandsInfoService.cs +++ b/Felicity/Services/Hosted/CommandsInfoService.cs @@ -1,79 +1,79 @@ -using System.Collections.ObjectModel; -using System.Reflection; -using Discord.Interactions; -using Felicity.Models.CommandsInfo; -using Felicity.Services.Hosted.Interfaces; -using Serilog; -using CommandParameterInfo = Felicity.Models.CommandsInfo.CommandParameterInfo; - -namespace Felicity.Services.Hosted; - -public class CommandsInfoService : ICommandsInfoService -{ - private readonly Type _baseCommandType = typeof(IInteractionModuleBase); - - public ReadOnlyCollection CommandsInfo { get; private set; } = null!; - - public void Initialize() - { - var commandsInfo = new List(); - var assembly = Assembly.GetAssembly(typeof(CommandsInfoService)); - - if (assembly is null) - { - Log.Error("Assembly failed to populate."); - return; - } - - var assemblyTypes = assembly.GetTypes(); - var commandTypes = assemblyTypes.Where(x => x.IsAssignableTo(_baseCommandType)).ToArray(); - - foreach (var commandType in commandTypes) - { - var groupAttribute = commandType.GetCustomAttribute(); - - if (groupAttribute is null) continue; - - var methods = commandType.GetMethods( - BindingFlags.Instance | - BindingFlags.Public | - BindingFlags.NonPublic); - - foreach (var methodData in methods) - { - var slashCommandAttribute = methodData.GetCustomAttribute(); - if (slashCommandAttribute is null) continue; - - var commandInfo = new CommandInfo( - $"{groupAttribute.Name} {slashCommandAttribute.Name}", - slashCommandAttribute.Description); - - var parameters = methodData.GetParameters(); - foreach (var parameter in parameters) - { - var commandParameterInfo = new CommandParameterInfo(); - var summaryAttribute = parameter.GetCustomAttribute(); - var autoCompleteAttribute = parameter.GetCustomAttribute(); - - if (summaryAttribute is not null) - { - commandParameterInfo.Name = summaryAttribute.Name; - commandParameterInfo.Description = summaryAttribute.Description; - } - else - { - commandParameterInfo.Name = parameter.Name!; - } - - if (autoCompleteAttribute is not null) commandParameterInfo.IsAutocomplete = true; - - commandInfo.ParametersInfo.Add(commandParameterInfo); - } - - commandsInfo.Add(commandInfo); - } - } - - CommandsInfo = new ReadOnlyCollection(commandsInfo); - } +using System.Collections.ObjectModel; +using System.Reflection; +using Discord.Interactions; +using Felicity.Models.CommandsInfo; +using Felicity.Services.Hosted.Interfaces; +using Serilog; +using CommandParameterInfo = Felicity.Models.CommandsInfo.CommandParameterInfo; + +namespace Felicity.Services.Hosted; + +public class CommandsInfoService : ICommandsInfoService +{ + private readonly Type _baseCommandType = typeof(IInteractionModuleBase); + + public ReadOnlyCollection CommandsInfo { get; private set; } = null!; + + public void Initialize() + { + var commandsInfo = new List(); + var assembly = Assembly.GetAssembly(typeof(CommandsInfoService)); + + if (assembly is null) + { + Log.Error("Assembly failed to populate."); + return; + } + + var assemblyTypes = assembly.GetTypes(); + var commandTypes = assemblyTypes.Where(x => x.IsAssignableTo(_baseCommandType)).ToArray(); + + foreach (var commandType in commandTypes) + { + var groupAttribute = commandType.GetCustomAttribute(); + + if (groupAttribute is null) continue; + + var methods = commandType.GetMethods( + BindingFlags.Instance | + BindingFlags.Public | + BindingFlags.NonPublic); + + foreach (var methodData in methods) + { + var slashCommandAttribute = methodData.GetCustomAttribute(); + if (slashCommandAttribute is null) continue; + + var commandInfo = new CommandInfo( + $"{groupAttribute.Name} {slashCommandAttribute.Name}", + slashCommandAttribute.Description); + + var parameters = methodData.GetParameters(); + foreach (var parameter in parameters) + { + var commandParameterInfo = new CommandParameterInfo(); + var summaryAttribute = parameter.GetCustomAttribute(); + var autoCompleteAttribute = parameter.GetCustomAttribute(); + + if (summaryAttribute is not null) + { + commandParameterInfo.Name = summaryAttribute.Name; + commandParameterInfo.Description = summaryAttribute.Description; + } + else + { + commandParameterInfo.Name = parameter.Name!; + } + + if (autoCompleteAttribute is not null) commandParameterInfo.IsAutocomplete = true; + + commandInfo.ParametersInfo.Add(commandParameterInfo); + } + + commandsInfo.Add(commandInfo); + } + } + + CommandsInfo = new ReadOnlyCollection(commandsInfo); + } } \ No newline at end of file diff --git a/Felicity/Services/Hosted/Interfaces/ICommandsInfoService.cs b/Felicity/Services/Hosted/Interfaces/ICommandsInfoService.cs index 84cfd9c..e709a5c 100644 --- a/Felicity/Services/Hosted/Interfaces/ICommandsInfoService.cs +++ b/Felicity/Services/Hosted/Interfaces/ICommandsInfoService.cs @@ -1,10 +1,10 @@ -using System.Collections.ObjectModel; -using Felicity.Models.CommandsInfo; - -namespace Felicity.Services.Hosted.Interfaces; - -public interface ICommandsInfoService -{ - ReadOnlyCollection CommandsInfo { get; } - void Initialize(); +using System.Collections.ObjectModel; +using Felicity.Models.CommandsInfo; + +namespace Felicity.Services.Hosted.Interfaces; + +public interface ICommandsInfoService +{ + ReadOnlyCollection CommandsInfo { get; } + void Initialize(); } \ No newline at end of file diff --git a/Felicity/Services/Hosted/ResetService.cs b/Felicity/Services/Hosted/ResetService.cs index 8ddcdcd..6728405 100644 --- a/Felicity/Services/Hosted/ResetService.cs +++ b/Felicity/Services/Hosted/ResetService.cs @@ -1,65 +1,65 @@ -using Discord.WebSocket; -using DotNetBungieAPI.Service.Abstractions; - -namespace Felicity.Services.Hosted; - -public class ResetService : BackgroundService -{ - private readonly IBungieClient _bungieClient; - - private readonly TimeSpan _delay = TimeSpan.FromMinutes(10); - private readonly DiscordShardedClient _discordClient; - private readonly ILogger _logger; - - public ResetService( - IBungieClient bungieClient, - DiscordShardedClient discordClient, - ILogger logger) - { - _bungieClient = bungieClient; - _discordClient = discordClient; - _logger = logger; - } - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - try - { - while (!stoppingToken.IsCancellationRequested) - { - await _bungieClient.ResetService.WaitForNextDailyReset(_delay, stoppingToken); - - _logger.LogInformation("Reset task starting"); - - switch (DateTime.UtcNow.DayOfWeek) - { - case DayOfWeek.Monday: - break; - case DayOfWeek.Tuesday: - // weekly reset - break; - case DayOfWeek.Wednesday: - // gunsmith weird perk reset time - break; - case DayOfWeek.Thursday: - break; - case DayOfWeek.Friday: - // xur & trials - break; - case DayOfWeek.Saturday: - break; - case DayOfWeek.Sunday: - break; - default: - throw new ArgumentOutOfRangeException(); - } - - // do stuff - } - } - catch (Exception e) - { - _logger.LogError(e, "Exception in ResetService"); - } - } +using Discord.WebSocket; +using DotNetBungieAPI.Service.Abstractions; + +namespace Felicity.Services.Hosted; + +public class ResetService : BackgroundService +{ + private readonly IBungieClient _bungieClient; + + private readonly TimeSpan _delay = TimeSpan.FromMinutes(10); + private readonly DiscordShardedClient _discordClient; + private readonly ILogger _logger; + + public ResetService( + IBungieClient bungieClient, + DiscordShardedClient discordClient, + ILogger logger) + { + _bungieClient = bungieClient; + _discordClient = discordClient; + _logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + try + { + while (!stoppingToken.IsCancellationRequested) + { + await _bungieClient.ResetService.WaitForNextDailyReset(_delay, stoppingToken); + + _logger.LogInformation("Reset task starting"); + + switch (DateTime.UtcNow.DayOfWeek) + { + case DayOfWeek.Monday: + break; + case DayOfWeek.Tuesday: + // weekly reset + break; + case DayOfWeek.Wednesday: + // gunsmith weird perk reset time + break; + case DayOfWeek.Thursday: + break; + case DayOfWeek.Friday: + // xur & trials + break; + case DayOfWeek.Saturday: + break; + case DayOfWeek.Sunday: + break; + default: + throw new ArgumentOutOfRangeException(); + } + + // do stuff + } + } + catch (Exception e) + { + _logger.LogError(e, "Exception in ResetService"); + } + } } \ No newline at end of file diff --git a/Felicity/Services/Hosted/StatusService.cs b/Felicity/Services/Hosted/StatusService.cs index 75b32b6..43aef3e 100644 --- a/Felicity/Services/Hosted/StatusService.cs +++ b/Felicity/Services/Hosted/StatusService.cs @@ -1,80 +1,80 @@ -using Discord; -using Discord.WebSocket; -using Felicity.Util; - -namespace Felicity.Services.Hosted; - -public class StatusService : BackgroundService -{ - private static readonly List GameList = new() - { - new Game("Destiny 3"), - new Game("Spire of Stars"), - new Game("you 👀", ActivityType.Watching), - new Game("Moons break stuff 🔨", ActivityType.Watching), - new Game("with fire"), - new Game("you break the rules", ActivityType.Watching), - new Game("Juice WRLD", ActivityType.Listening), - new Game("Google Chrome"), - new Game("$10k qp tourney", ActivityType.Competing), - new Game("sweet bird sounds", ActivityType.Listening), - new Game("Felicity ... wait", ActivityType.Watching), - new Game($"v.{BotVariables.Version}"), - new Game("/lookup", ActivityType.Watching), - new Game("hide & seek in the Tower"), - new Game("/metrics", ActivityType.Watching), - new Game("/vendor", ActivityType.Watching), - new Game("/loot-table", ActivityType.Watching), - new Game("/recipes", ActivityType.Watching), - new Game("/memento", ActivityType.Watching), - new Game("big /checkpoint hurting mom & pop LFG", ActivityType.Watching) - }; - - private readonly TimeSpan _delay = TimeSpan.FromMinutes(15); - private readonly DiscordShardedClient _discordClient; - private readonly ILogger _logger; - - public StatusService( - DiscordShardedClient discordClient, - ILogger logger) - { - _discordClient = discordClient; - _logger = logger; - } - - private static Game LastGame { get; set; } = null!; - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - try - { - await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken); - - while (!stoppingToken.IsCancellationRequested) - { - Game newGame; - do - { - newGame = GameList[Random.Shared.Next(GameList.Count)]; - } while (newGame == LastGame); - - try - { - await _discordClient.SetActivityAsync(newGame); - _logger.LogInformation("Set game to: {Name}", newGame.Name); - LastGame = newGame; - } - catch - { - // ignored - } - - await Task.Delay(_delay, stoppingToken); - } - } - catch (Exception e) - { - _logger.LogError(e, "Exception in StatusService"); - } - } +using Discord; +using Discord.WebSocket; +using Felicity.Util; + +namespace Felicity.Services.Hosted; + +public class StatusService : BackgroundService +{ + private static readonly List GameList = new() + { + new Game("Destiny 3"), + new Game("Spire of Stars"), + new Game("you 👀", ActivityType.Watching), + new Game("Moons break stuff 🔨", ActivityType.Watching), + new Game("with fire"), + new Game("you break the rules", ActivityType.Watching), + new Game("Juice WRLD", ActivityType.Listening), + new Game("Google Chrome"), + new Game("$10k qp tourney", ActivityType.Competing), + new Game("sweet bird sounds", ActivityType.Listening), + new Game("Felicity ... wait", ActivityType.Watching), + new Game($"v.{BotVariables.Version}"), + new Game("/lookup", ActivityType.Watching), + new Game("hide & seek in the Tower"), + new Game("/metrics", ActivityType.Watching), + new Game("/vendor", ActivityType.Watching), + new Game("/loot-table", ActivityType.Watching), + new Game("/recipes", ActivityType.Watching), + new Game("/memento", ActivityType.Watching), + new Game("big /checkpoint hurting mom & pop LFG", ActivityType.Watching) + }; + + private readonly TimeSpan _delay = TimeSpan.FromMinutes(15); + private readonly DiscordShardedClient _discordClient; + private readonly ILogger _logger; + + public StatusService( + DiscordShardedClient discordClient, + ILogger logger) + { + _discordClient = discordClient; + _logger = logger; + } + + private static Game LastGame { get; set; } = null!; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + try + { + await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken); + + while (!stoppingToken.IsCancellationRequested) + { + Game newGame; + do + { + newGame = GameList[Random.Shared.Next(GameList.Count)]; + } while (newGame == LastGame); + + try + { + await _discordClient.SetActivityAsync(newGame); + _logger.LogInformation("Set game to: {Name}", newGame.Name); + LastGame = newGame; + } + catch + { + // ignored + } + + await Task.Delay(_delay, stoppingToken); + } + } + catch (Exception e) + { + _logger.LogError(e, "Exception in StatusService"); + } + } } \ No newline at end of file diff --git a/Felicity/Util/EmblemReport.cs b/Felicity/Util/EmblemReport.cs index 944cd51..417053b 100644 --- a/Felicity/Util/EmblemReport.cs +++ b/Felicity/Util/EmblemReport.cs @@ -1,33 +1,33 @@ -using System.Text.Json; -using System.Text.Json.Serialization; - -// ReSharper disable UnassignedGetOnlyAutoProperty -// ReSharper disable ClassNeverInstantiated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global - -namespace Felicity.Util; - -public class EmblemReport -{ - public partial class EmblemResponse - { - [JsonPropertyName("data")] public List Data { get; set; } = null!; - } - - public class Datum - { - [JsonPropertyName("collectible_hash")] public uint CollectibleHash { get; set; } - - [JsonPropertyName("acquisition")] public long Acquisition { get; set; } - - [JsonPropertyName("percentage")] public double Percentage { get; set; } - } - - public partial class EmblemResponse - { - public static EmblemResponse? FromJson(string json) - { - return JsonSerializer.Deserialize(json); - } - } +using System.Text.Json; +using System.Text.Json.Serialization; + +// ReSharper disable UnassignedGetOnlyAutoProperty +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global + +namespace Felicity.Util; + +public class EmblemReport +{ + public partial class EmblemResponse + { + [JsonPropertyName("data")] public List Data { get; set; } = null!; + } + + public class Datum + { + [JsonPropertyName("collectible_hash")] public uint CollectibleHash { get; set; } + + [JsonPropertyName("acquisition")] public long Acquisition { get; set; } + + [JsonPropertyName("percentage")] public double Percentage { get; set; } + } + + public partial class EmblemResponse + { + public static EmblemResponse? FromJson(string json) + { + return JsonSerializer.Deserialize(json); + } + } } \ No newline at end of file diff --git a/Felicity/Util/Enums/LootTables.cs b/Felicity/Util/Enums/LootTables.cs index 080a6a9..4ce1cf9 100644 --- a/Felicity/Util/Enums/LootTables.cs +++ b/Felicity/Util/Enums/LootTables.cs @@ -1,690 +1,690 @@ -using DotNetBungieAPI.HashReferences; - -// ReSharper disable UnusedAutoPropertyAccessor.Global - -namespace Felicity.Util.Enums; - -public class LootTableDefinition -{ - public string? Name { get; init; } - public string? Description { get; init; } - public ActivityType? ActivityType { get; init; } - public List? Loot { get; init; } -} - -public class LootTable -{ - public Encounter EncounterType { get; init; } - public string? EncounterName { get; init; } - public List? LootIds { get; init; } -} - -public enum ActivityType -{ - Dungeon, - Raid -} - -public enum Armor -{ - Helmet, - Gloves, - Chest, - Boots, - Class, - Everything, - None -} - -public enum Encounter -{ - First, - Second, - Third, - Fourth, - Fifth, - Boss -} - -public static class LootTables -{ - public static readonly List KnownTables = new() - { - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "Crota's End", - Description = "The Dark Below", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "The Abyss", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Chest, - DefinitionHashes.InventoryItems.AbyssDefiant_833898322, - DefinitionHashes.InventoryItems.FangofIrYût_1432682459, - DefinitionHashes.InventoryItems.SongofIrYût_2828278545 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "The Bridge", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.FangofIrYût_1432682459, - DefinitionHashes.InventoryItems.Swordbreaker_3163900678, - DefinitionHashes.InventoryItems.OversoulEdict_1098171824 - } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "Ir Yût, the Deathsinger", - LootIds = new List - { - (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.OversoulEdict_1098171824, - DefinitionHashes.InventoryItems.SongofIrYût_2828278545, - DefinitionHashes.InventoryItems.WordofCrota_120706239 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Crota, Son of Oryx", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.AbyssDefiant_833898322, - DefinitionHashes.InventoryItems.Swordbreaker_3163900678, - DefinitionHashes.InventoryItems.WordofCrota_120706239 - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "Root of Nightmares", - Description = "A sinister threat has taken root.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Survive the Onslaught", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Chest, - DefinitionHashes.InventoryItems.BriarsContempt_1491665733, - DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, - DefinitionHashes.InventoryItems.NessasOblation_135029084 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Enter the Root", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.AcasiasDejection_1471212226, - DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, - DefinitionHashes.InventoryItems.MykelsReverence_231031173, - DefinitionHashes.InventoryItems.NessasOblation_135029084 - } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "Zo'aurc, Explicator of Planets", - LootIds = new List - { - (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.AcasiasDejection_1471212226, - DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, - DefinitionHashes.InventoryItems.MykelsReverence_231031173, - DefinitionHashes.InventoryItems.RufussFury_484515708 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Nezarec, Final God of Pain", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.ConditionalFinality, - DefinitionHashes.InventoryItems.AcasiasDejection_1471212226, - DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, - DefinitionHashes.InventoryItems.MykelsReverence_231031173, - DefinitionHashes.InventoryItems.NessasOblation_135029084, - DefinitionHashes.InventoryItems.RufussFury_484515708 - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "King's Fall", Description = "Long live the King...", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Gate", - LootIds = new List - { - (uint)Armor.Class, - DefinitionHashes.InventoryItems.DoomofChelchis_1937552980 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Totems", - LootIds = new List - { - (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.DoomofChelchis_1937552980, - DefinitionHashes.InventoryItems.QullimsTerminus_1321506184 - } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "Warpriest", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, - DefinitionHashes.InventoryItems.SmiteofMerain_2221264583, - DefinitionHashes.InventoryItems.DefianceofYasmin_3228096719 - } - }, - new() - { - EncounterType = Encounter.Fourth, EncounterName = "Golgoroth", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.QullimsTerminus_1321506184, - DefinitionHashes.InventoryItems.ZaoulisBane_431721920, - DefinitionHashes.InventoryItems.MidhasReckoning_3969066556 - } - }, - new() - { - EncounterType = Encounter.Fifth, EncounterName = "Daughters", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, - DefinitionHashes.InventoryItems.QullimsTerminus_1321506184, - DefinitionHashes.InventoryItems.SmiteofMerain_2221264583, - DefinitionHashes.InventoryItems.ZaoulisBane_431721920 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Oryx, The Taken King", - LootIds = new List - { - (uint)Armor.Helmet, - DefinitionHashes.InventoryItems.MidhasReckoning_3969066556, - DefinitionHashes.InventoryItems.TouchofMalice_1802135586 - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "Vow of the Disciple", Description = "The disciple beckons...", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Acquisition", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Chest, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.Deliverance_768621510, - DefinitionHashes.InventoryItems.Submission_3886416794, - DefinitionHashes.InventoryItems.Cataclysmic_999767358 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Collection", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Class, - DefinitionHashes.InventoryItems.Submission_3886416794, - DefinitionHashes.InventoryItems.Forbearance_613334176, - DefinitionHashes.InventoryItems.Insidious_3428521585, - DefinitionHashes.InventoryItems.Cataclysmic_999767358 - } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "Exhibition", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Chest, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.Deliverance_768621510, - DefinitionHashes.InventoryItems.Submission_3886416794 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Dominion", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Class, - DefinitionHashes.InventoryItems.CollectiveObligation, - DefinitionHashes.InventoryItems.Forbearance_613334176, - DefinitionHashes.InventoryItems.Insidious_3428521585, - DefinitionHashes.InventoryItems.LubraesRuin_2534546147 - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "Vault of Glass", Description = - "Beneath Venus, evil stirs...\n\n" + - "Timelost weapons require **Master** challenge completion on that encounter while VoG is the active rotator raid.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Confluxes", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Class, - DefinitionHashes.InventoryItems.FoundVerdict_3197270240, - DefinitionHashes.InventoryItems.CorrectiveMeasure_471518543, - DefinitionHashes.InventoryItems.VisionofConfluence_3186018373, - DefinitionHashes.InventoryItems.VisionofConfluenceTimelost_690668916 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Oracles", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.PraedythsRevenge_3653573172, - DefinitionHashes.InventoryItems.FoundVerdict_3197270240, - DefinitionHashes.InventoryItems.VisionofConfluence_3186018373, - DefinitionHashes.InventoryItems.PraedythsRevengeTimelost_1987769101 - } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "The Templar", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, - DefinitionHashes.InventoryItems.Fatebringer_2171478765, - DefinitionHashes.InventoryItems.VisionofConfluence_3186018373, - DefinitionHashes.InventoryItems.CorrectiveMeasure_471518543, - DefinitionHashes.InventoryItems.FatebringerTimelost_1216319404 - } - }, - new() - { - EncounterType = Encounter.Fourth, EncounterName = "The Gatekeepers", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.Fatebringer_2171478765, - DefinitionHashes.InventoryItems.FoundVerdict_3197270240, - DefinitionHashes.InventoryItems.HezenVengeance_4050645223, - DefinitionHashes.InventoryItems.HezenVengeanceTimelost_1921159786 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Atheon, Time's Conflux", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Chest, - DefinitionHashes.InventoryItems.VexMythoclast, - DefinitionHashes.InventoryItems.PraedythsRevenge_3653573172, - DefinitionHashes.InventoryItems.CorrectiveMeasure_471518543, - DefinitionHashes.InventoryItems.HezenVengeance_4050645223, - DefinitionHashes.InventoryItems.CorrectiveMeasureTimelost_3796510434 - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "Deep Stone Crypt", - Description = "The chains of legacy must be broken.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Crypt Security", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.Trustee_1392919471 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Atraks-1", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.Heritage_4248569242, - DefinitionHashes.InventoryItems.Succession_2990047042 - } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "Taniks, Reborn", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, - DefinitionHashes.InventoryItems.Heritage_4248569242, - DefinitionHashes.InventoryItems.Posterity_3281285075 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Taniks, The Abomination", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Chest, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.EyesofTomorrow, - DefinitionHashes.InventoryItems.Bequest_3366545721, - DefinitionHashes.InventoryItems.Commemoration_4230965989 - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "Garden of Salvation", - Description = "The Garden calls out to you.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Evade the Consecrated Mind", - LootIds = new List - { - (uint)Armor.Boots, - DefinitionHashes.InventoryItems.AccruedRedemption, - DefinitionHashes.InventoryItems.ZealotsReward - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Summon the Consecrated Mind", - LootIds = new List - { - (uint)Armor.Gloves, - DefinitionHashes.InventoryItems.ProphetofDoom, - DefinitionHashes.InventoryItems.RecklessOracle - } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "Defeat the Consecrated Mind", - LootIds = new List - { - (uint)Armor.Chest, - DefinitionHashes.InventoryItems.SacredProvenance, - DefinitionHashes.InventoryItems.AncientGospel - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "The Sanctified Mind", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Class, - DefinitionHashes.InventoryItems.OmniscientEye - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Raid, Name = "Last Wish", Description = "The opportunity of a lifetime.\n\n" + - "Last Wish drops are unique in that anything can drop from anywhere except key items shown below.\n" + - "Weapons indicated here are curated roll drops.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Kalli, The Corrupted", - LootIds = new List { DefinitionHashes.InventoryItems.AgeOldBond_601592879 } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Shuro Chi, The Corrupted", - LootIds = new List { DefinitionHashes.InventoryItems.Transfiguration_3799980700 } - }, - new() - { - EncounterType = Encounter.Third, EncounterName = "Morgeth, The Spirekeeper", - LootIds = new List - { - DefinitionHashes.InventoryItems.NationofBeasts_654370424, - DefinitionHashes.InventoryItems.CleansingKnife - } - }, - new() - { - EncounterType = Encounter.Fourth, EncounterName = "The Vault", - LootIds = new List { DefinitionHashes.InventoryItems.TyrannyofHeaven_2721249463 } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Riven of a Thousand Voices", - LootIds = new List - { - DefinitionHashes.InventoryItems.ChatteringBone_568515759, - DefinitionHashes.InventoryItems.GlitteringKey - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Dungeon, Name = "Ghosts of the Deep", - Description = "Drown in the deep, or rise from it.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Hive Ritual", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.NoSurvivors_3262192268, - DefinitionHashes.InventoryItems.NewPacificEpitaph, - DefinitionHashes.InventoryItems.ColdComfort_839786290 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Ecthar, Shield of Savathûn", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, - DefinitionHashes.InventoryItems.NoSurvivors_3262192268, - DefinitionHashes.InventoryItems.GreasyLuck, - DefinitionHashes.InventoryItems.ColdComfort_839786290 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Simmumah ur-Nokru", - LootIds = new List - { - DefinitionHashes.InventoryItems.TheNavigator, - DefinitionHashes.InventoryItems.NoSurvivors_3262192268, - DefinitionHashes.InventoryItems.NewPacificEpitaph, - DefinitionHashes.InventoryItems.ColdComfort_839786290, - DefinitionHashes.InventoryItems.GreasyLuck, - (uint)Armor.Everything - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Dungeon, Name = "Spire of the Watcher", - Description = "Machinations run wild in this dust-ridden ruin. Bring them to heel.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Ascend the Spire", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.LongArm, - DefinitionHashes.InventoryItems.SeventhSeraphCarbine_4070357005, - DefinitionHashes.InventoryItems.TerminusHorizon - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Silence the Spire", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, - DefinitionHashes.InventoryItems.SeventhSeraphOfficerRevolver_1555959830, - DefinitionHashes.InventoryItems.TerminusHorizon - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Persys, Primordial Ruin", - LootIds = new List - { - DefinitionHashes.InventoryItems.HierarchyofNeeds, - DefinitionHashes.InventoryItems.LiminalVigil, - DefinitionHashes.InventoryItems.LongArm, - DefinitionHashes.InventoryItems.SeventhSeraphCarbine_4070357005, - DefinitionHashes.InventoryItems.SeventhSeraphOfficerRevolver_1555959830, - DefinitionHashes.InventoryItems.TerminusHorizon, - DefinitionHashes.InventoryItems.Wilderflight, - (uint)Armor.Everything - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Dungeon, Name = "Duality", - Description = "Dive into the depths of the exiled emperor's mind in search of dark secrets.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Sorrow Bearer", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Boots, - DefinitionHashes.InventoryItems.LingeringDread, - DefinitionHashes.InventoryItems.TheEpicurean_2263839058 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "The Vault", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, - DefinitionHashes.InventoryItems.Unforgiven, - DefinitionHashes.InventoryItems.Stormchaser - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Calus' Greatest Shame", - LootIds = new List - { - DefinitionHashes.InventoryItems.Heartshadow, - DefinitionHashes.InventoryItems.NewPurpose, - DefinitionHashes.InventoryItems.FixedOdds_1642384931, - (uint)Armor.Everything - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Dungeon, Name = "Grasp of Avarice", - Description = "A cautionary tale for adventurers willing to trade their humanity for riches.", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Phry'zia, The Insatiable", - LootIds = new List - { - (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.Matador64 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "Sunken Lair", - LootIds = new List - { - (uint)Armor.Gloves, (uint)Armor.Chest, - DefinitionHashes.InventoryItems.HeroofAges - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Avarokk, The Covetous", - LootIds = new List - { - DefinitionHashes.InventoryItems.Eyasluna, - DefinitionHashes.InventoryItems.H1000YardStare, - (uint)Armor.Everything - } - } - } - }, - new LootTableDefinition - { - ActivityType = ActivityType.Dungeon, Name = "Prophecy", - Description = "Enter the realm of the Nine and ask the question: \"What is the nature of the Darkness?\"", - Loot = new List - { - new() - { - EncounterType = Encounter.First, EncounterName = "Phalanx Echo", - LootIds = new List - { - (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.Judgment_1476654960, - DefinitionHashes.InventoryItems.TheLongWalk_3326850591 - } - }, - new() - { - EncounterType = Encounter.Second, EncounterName = "The Cube", - LootIds = new List - { - (uint)Armor.Gloves, - DefinitionHashes.InventoryItems.ASwiftVerdict_1626503676, - DefinitionHashes.InventoryItems.TheLastBreath_507038823 - } - }, - new() - { - EncounterType = Encounter.Boss, EncounterName = "Kell Echo", - LootIds = new List - { - (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, - DefinitionHashes.InventoryItems.DarkestBefore_2481758391, - DefinitionHashes.InventoryItems.ASuddenDeath_2855157553 - } - } - } - } - }; +using DotNetBungieAPI.HashReferences; + +// ReSharper disable UnusedAutoPropertyAccessor.Global + +namespace Felicity.Util.Enums; + +public class LootTableDefinition +{ + public string? Name { get; init; } + public string? Description { get; init; } + public ActivityType? ActivityType { get; init; } + public List? Loot { get; init; } +} + +public class LootTable +{ + public Encounter EncounterType { get; init; } + public string? EncounterName { get; init; } + public List? LootIds { get; init; } +} + +public enum ActivityType +{ + Dungeon, + Raid +} + +public enum Armor +{ + Helmet, + Gloves, + Chest, + Boots, + Class, + Everything, + None +} + +public enum Encounter +{ + First, + Second, + Third, + Fourth, + Fifth, + Boss +} + +public static class LootTables +{ + public static readonly List KnownTables = new() + { + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "Crota's End", + Description = "The Dark Below", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "The Abyss", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Chest, + DefinitionHashes.InventoryItems.AbyssDefiant_833898322, + DefinitionHashes.InventoryItems.FangofIrYût_1432682459, + DefinitionHashes.InventoryItems.SongofIrYût_2828278545 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "The Bridge", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.FangofIrYût_1432682459, + DefinitionHashes.InventoryItems.Swordbreaker_3163900678, + DefinitionHashes.InventoryItems.OversoulEdict_1098171824 + } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "Ir Yût, the Deathsinger", + LootIds = new List + { + (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.OversoulEdict_1098171824, + DefinitionHashes.InventoryItems.SongofIrYût_2828278545, + DefinitionHashes.InventoryItems.WordofCrota_120706239 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Crota, Son of Oryx", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.AbyssDefiant_833898322, + DefinitionHashes.InventoryItems.Swordbreaker_3163900678, + DefinitionHashes.InventoryItems.WordofCrota_120706239 + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "Root of Nightmares", + Description = "A sinister threat has taken root.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Survive the Onslaught", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Chest, + DefinitionHashes.InventoryItems.BriarsContempt_1491665733, + DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, + DefinitionHashes.InventoryItems.NessasOblation_135029084 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Enter the Root", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.AcasiasDejection_1471212226, + DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, + DefinitionHashes.InventoryItems.MykelsReverence_231031173, + DefinitionHashes.InventoryItems.NessasOblation_135029084 + } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "Zo'aurc, Explicator of Planets", + LootIds = new List + { + (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.AcasiasDejection_1471212226, + DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, + DefinitionHashes.InventoryItems.MykelsReverence_231031173, + DefinitionHashes.InventoryItems.RufussFury_484515708 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Nezarec, Final God of Pain", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.ConditionalFinality, + DefinitionHashes.InventoryItems.AcasiasDejection_1471212226, + DefinitionHashes.InventoryItems.KoraxissDistress_2972949637, + DefinitionHashes.InventoryItems.MykelsReverence_231031173, + DefinitionHashes.InventoryItems.NessasOblation_135029084, + DefinitionHashes.InventoryItems.RufussFury_484515708 + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "King's Fall", Description = "Long live the King...", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Gate", + LootIds = new List + { + (uint)Armor.Class, + DefinitionHashes.InventoryItems.DoomofChelchis_1937552980 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Totems", + LootIds = new List + { + (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.DoomofChelchis_1937552980, + DefinitionHashes.InventoryItems.QullimsTerminus_1321506184 + } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "Warpriest", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, + DefinitionHashes.InventoryItems.SmiteofMerain_2221264583, + DefinitionHashes.InventoryItems.DefianceofYasmin_3228096719 + } + }, + new() + { + EncounterType = Encounter.Fourth, EncounterName = "Golgoroth", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.QullimsTerminus_1321506184, + DefinitionHashes.InventoryItems.ZaoulisBane_431721920, + DefinitionHashes.InventoryItems.MidhasReckoning_3969066556 + } + }, + new() + { + EncounterType = Encounter.Fifth, EncounterName = "Daughters", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, + DefinitionHashes.InventoryItems.QullimsTerminus_1321506184, + DefinitionHashes.InventoryItems.SmiteofMerain_2221264583, + DefinitionHashes.InventoryItems.ZaoulisBane_431721920 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Oryx, The Taken King", + LootIds = new List + { + (uint)Armor.Helmet, + DefinitionHashes.InventoryItems.MidhasReckoning_3969066556, + DefinitionHashes.InventoryItems.TouchofMalice_1802135586 + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "Vow of the Disciple", Description = "The disciple beckons...", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Acquisition", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Chest, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.Deliverance_768621510, + DefinitionHashes.InventoryItems.Submission_3886416794, + DefinitionHashes.InventoryItems.Cataclysmic_999767358 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Collection", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Class, + DefinitionHashes.InventoryItems.Submission_3886416794, + DefinitionHashes.InventoryItems.Forbearance_613334176, + DefinitionHashes.InventoryItems.Insidious_3428521585, + DefinitionHashes.InventoryItems.Cataclysmic_999767358 + } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "Exhibition", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Chest, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.Deliverance_768621510, + DefinitionHashes.InventoryItems.Submission_3886416794 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Dominion", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Class, + DefinitionHashes.InventoryItems.CollectiveObligation, + DefinitionHashes.InventoryItems.Forbearance_613334176, + DefinitionHashes.InventoryItems.Insidious_3428521585, + DefinitionHashes.InventoryItems.LubraesRuin_2534546147 + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "Vault of Glass", Description = + "Beneath Venus, evil stirs...\n\n" + + "Timelost weapons require **Master** challenge completion on that encounter while VoG is the active rotator raid.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Confluxes", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Class, + DefinitionHashes.InventoryItems.FoundVerdict_3197270240, + DefinitionHashes.InventoryItems.CorrectiveMeasure_471518543, + DefinitionHashes.InventoryItems.VisionofConfluence_3186018373, + DefinitionHashes.InventoryItems.VisionofConfluenceTimelost_690668916 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Oracles", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.PraedythsRevenge_3653573172, + DefinitionHashes.InventoryItems.FoundVerdict_3197270240, + DefinitionHashes.InventoryItems.VisionofConfluence_3186018373, + DefinitionHashes.InventoryItems.PraedythsRevengeTimelost_1987769101 + } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "The Templar", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, + DefinitionHashes.InventoryItems.Fatebringer_2171478765, + DefinitionHashes.InventoryItems.VisionofConfluence_3186018373, + DefinitionHashes.InventoryItems.CorrectiveMeasure_471518543, + DefinitionHashes.InventoryItems.FatebringerTimelost_1216319404 + } + }, + new() + { + EncounterType = Encounter.Fourth, EncounterName = "The Gatekeepers", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.Fatebringer_2171478765, + DefinitionHashes.InventoryItems.FoundVerdict_3197270240, + DefinitionHashes.InventoryItems.HezenVengeance_4050645223, + DefinitionHashes.InventoryItems.HezenVengeanceTimelost_1921159786 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Atheon, Time's Conflux", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Chest, + DefinitionHashes.InventoryItems.VexMythoclast, + DefinitionHashes.InventoryItems.PraedythsRevenge_3653573172, + DefinitionHashes.InventoryItems.CorrectiveMeasure_471518543, + DefinitionHashes.InventoryItems.HezenVengeance_4050645223, + DefinitionHashes.InventoryItems.CorrectiveMeasureTimelost_3796510434 + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "Deep Stone Crypt", + Description = "The chains of legacy must be broken.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Crypt Security", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.Trustee_1392919471 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Atraks-1", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.Heritage_4248569242, + DefinitionHashes.InventoryItems.Succession_2990047042 + } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "Taniks, Reborn", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, + DefinitionHashes.InventoryItems.Heritage_4248569242, + DefinitionHashes.InventoryItems.Posterity_3281285075 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Taniks, The Abomination", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Chest, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.EyesofTomorrow, + DefinitionHashes.InventoryItems.Bequest_3366545721, + DefinitionHashes.InventoryItems.Commemoration_4230965989 + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "Garden of Salvation", + Description = "The Garden calls out to you.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Evade the Consecrated Mind", + LootIds = new List + { + (uint)Armor.Boots, + DefinitionHashes.InventoryItems.AccruedRedemption, + DefinitionHashes.InventoryItems.ZealotsReward + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Summon the Consecrated Mind", + LootIds = new List + { + (uint)Armor.Gloves, + DefinitionHashes.InventoryItems.ProphetofDoom, + DefinitionHashes.InventoryItems.RecklessOracle + } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "Defeat the Consecrated Mind", + LootIds = new List + { + (uint)Armor.Chest, + DefinitionHashes.InventoryItems.SacredProvenance, + DefinitionHashes.InventoryItems.AncientGospel + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "The Sanctified Mind", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Class, + DefinitionHashes.InventoryItems.OmniscientEye + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Raid, Name = "Last Wish", Description = "The opportunity of a lifetime.\n\n" + + "Last Wish drops are unique in that anything can drop from anywhere except key items shown below.\n" + + "Weapons indicated here are curated roll drops.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Kalli, The Corrupted", + LootIds = new List { DefinitionHashes.InventoryItems.AgeOldBond_601592879 } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Shuro Chi, The Corrupted", + LootIds = new List { DefinitionHashes.InventoryItems.Transfiguration_3799980700 } + }, + new() + { + EncounterType = Encounter.Third, EncounterName = "Morgeth, The Spirekeeper", + LootIds = new List + { + DefinitionHashes.InventoryItems.NationofBeasts_654370424, + DefinitionHashes.InventoryItems.CleansingKnife + } + }, + new() + { + EncounterType = Encounter.Fourth, EncounterName = "The Vault", + LootIds = new List { DefinitionHashes.InventoryItems.TyrannyofHeaven_2721249463 } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Riven of a Thousand Voices", + LootIds = new List + { + DefinitionHashes.InventoryItems.ChatteringBone_568515759, + DefinitionHashes.InventoryItems.GlitteringKey + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Dungeon, Name = "Ghosts of the Deep", + Description = "Drown in the deep, or rise from it.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Hive Ritual", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.NoSurvivors_3262192268, + DefinitionHashes.InventoryItems.NewPacificEpitaph, + DefinitionHashes.InventoryItems.ColdComfort_839786290 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Ecthar, Shield of Savathûn", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, + DefinitionHashes.InventoryItems.NoSurvivors_3262192268, + DefinitionHashes.InventoryItems.GreasyLuck, + DefinitionHashes.InventoryItems.ColdComfort_839786290 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Simmumah ur-Nokru", + LootIds = new List + { + DefinitionHashes.InventoryItems.TheNavigator, + DefinitionHashes.InventoryItems.NoSurvivors_3262192268, + DefinitionHashes.InventoryItems.NewPacificEpitaph, + DefinitionHashes.InventoryItems.ColdComfort_839786290, + DefinitionHashes.InventoryItems.GreasyLuck, + (uint)Armor.Everything + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Dungeon, Name = "Spire of the Watcher", + Description = "Machinations run wild in this dust-ridden ruin. Bring them to heel.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Ascend the Spire", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.LongArm, + DefinitionHashes.InventoryItems.SeventhSeraphCarbine_4070357005, + DefinitionHashes.InventoryItems.TerminusHorizon + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Silence the Spire", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, + DefinitionHashes.InventoryItems.SeventhSeraphOfficerRevolver_1555959830, + DefinitionHashes.InventoryItems.TerminusHorizon + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Persys, Primordial Ruin", + LootIds = new List + { + DefinitionHashes.InventoryItems.HierarchyofNeeds, + DefinitionHashes.InventoryItems.LiminalVigil, + DefinitionHashes.InventoryItems.LongArm, + DefinitionHashes.InventoryItems.SeventhSeraphCarbine_4070357005, + DefinitionHashes.InventoryItems.SeventhSeraphOfficerRevolver_1555959830, + DefinitionHashes.InventoryItems.TerminusHorizon, + DefinitionHashes.InventoryItems.Wilderflight, + (uint)Armor.Everything + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Dungeon, Name = "Duality", + Description = "Dive into the depths of the exiled emperor's mind in search of dark secrets.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Sorrow Bearer", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Boots, + DefinitionHashes.InventoryItems.LingeringDread, + DefinitionHashes.InventoryItems.TheEpicurean_2263839058 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "The Vault", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Class, + DefinitionHashes.InventoryItems.Unforgiven, + DefinitionHashes.InventoryItems.Stormchaser + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Calus' Greatest Shame", + LootIds = new List + { + DefinitionHashes.InventoryItems.Heartshadow, + DefinitionHashes.InventoryItems.NewPurpose, + DefinitionHashes.InventoryItems.FixedOdds_1642384931, + (uint)Armor.Everything + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Dungeon, Name = "Grasp of Avarice", + Description = "A cautionary tale for adventurers willing to trade their humanity for riches.", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Phry'zia, The Insatiable", + LootIds = new List + { + (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.Matador64 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "Sunken Lair", + LootIds = new List + { + (uint)Armor.Gloves, (uint)Armor.Chest, + DefinitionHashes.InventoryItems.HeroofAges + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Avarokk, The Covetous", + LootIds = new List + { + DefinitionHashes.InventoryItems.Eyasluna, + DefinitionHashes.InventoryItems.H1000YardStare, + (uint)Armor.Everything + } + } + } + }, + new LootTableDefinition + { + ActivityType = ActivityType.Dungeon, Name = "Prophecy", + Description = "Enter the realm of the Nine and ask the question: \"What is the nature of the Darkness?\"", + Loot = new List + { + new() + { + EncounterType = Encounter.First, EncounterName = "Phalanx Echo", + LootIds = new List + { + (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.Judgment_1476654960, + DefinitionHashes.InventoryItems.TheLongWalk_3326850591 + } + }, + new() + { + EncounterType = Encounter.Second, EncounterName = "The Cube", + LootIds = new List + { + (uint)Armor.Gloves, + DefinitionHashes.InventoryItems.ASwiftVerdict_1626503676, + DefinitionHashes.InventoryItems.TheLastBreath_507038823 + } + }, + new() + { + EncounterType = Encounter.Boss, EncounterName = "Kell Echo", + LootIds = new List + { + (uint)Armor.Helmet, (uint)Armor.Gloves, (uint)Armor.Chest, (uint)Armor.Boots, (uint)Armor.Class, + DefinitionHashes.InventoryItems.DarkestBefore_2481758391, + DefinitionHashes.InventoryItems.ASuddenDeath_2855157553 + } + } + } + } + }; } \ No newline at end of file diff --git a/Felicity/Util/HttpClientInstance.cs b/Felicity/Util/HttpClientInstance.cs index 9db2609..625c08f 100644 --- a/Felicity/Util/HttpClientInstance.cs +++ b/Felicity/Util/HttpClientInstance.cs @@ -1,8 +1,8 @@ -namespace Felicity.Util; - -public static class HttpClientInstance -{ - private static readonly HttpClient? _httpClient; - - public static HttpClient Instance => _httpClient ?? new HttpClient(); +namespace Felicity.Util; + +public static class HttpClientInstance +{ + private static readonly HttpClient? _httpClient; + + public static HttpClient Instance => _httpClient ?? new HttpClient(); } \ No newline at end of file diff --git a/Felicity/Util/ProfileHelper.cs b/Felicity/Util/ProfileHelper.cs index 7fb187d..82c050f 100644 --- a/Felicity/Util/ProfileHelper.cs +++ b/Felicity/Util/ProfileHelper.cs @@ -1,61 +1,61 @@ -using DotNetBungieAPI.Models; -using DotNetBungieAPI.Service.Abstractions; -using Felicity.Models; - -namespace Felicity.Util; - -public abstract class ProfileHelper -{ - public static async Task GetRequestedProfile( - string bungieTag, - ulong discordId, - UserDb userDb, - IBungieClient bungieClient) - { - var profile = new ProfileResponse(); - - if (string.IsNullOrEmpty(bungieTag)) - { - var currentUser = userDb.Users.FirstOrDefault(x => x.DiscordId == discordId); - - if (currentUser == null) - { - profile.Error = - "You haven't specified a Bungie name to look up. If you want to use your own account, please register with '/user register' first." - + "Alternatively, you can provide a specific name to search for."; - return profile; - } - - profile.MembershipId = currentUser.DestinyMembershipId; - profile.MembershipType = currentUser.DestinyMembershipType; - profile.BungieName = currentUser.BungieName; - - return profile; - } - - var name = bungieTag.Split("#").First(); - var code = Convert.ToInt16(bungieTag.Split("#").Last()); - - var goodProfile = await BungieApiUtils.GetLatestProfileAsync(bungieClient, name, code); - if (goodProfile == null || goodProfile.MembershipType == BungieMembershipType.None) - { - profile.Error = - $"No profiles found matching `{bungieTag}`.\nThis can happen if no characters are currently on the Bungie account."; - return profile; - } - - profile.MembershipId = goodProfile.MembershipId; - profile.MembershipType = goodProfile.MembershipType; - profile.BungieName = $"{goodProfile.BungieGlobalDisplayName}#{goodProfile.BungieGlobalDisplayNameCode}"; - - return profile; - } - - public class ProfileResponse - { - public string? Error { get; set; } - public long MembershipId { get; set; } - public BungieMembershipType MembershipType { get; set; } - public string? BungieName { get; set; } - } +using DotNetBungieAPI.Models; +using DotNetBungieAPI.Service.Abstractions; +using Felicity.Models; + +namespace Felicity.Util; + +public abstract class ProfileHelper +{ + public static async Task GetRequestedProfile( + string bungieTag, + ulong discordId, + UserDb userDb, + IBungieClient bungieClient) + { + var profile = new ProfileResponse(); + + if (string.IsNullOrEmpty(bungieTag)) + { + var currentUser = userDb.Users.FirstOrDefault(x => x.DiscordId == discordId); + + if (currentUser == null) + { + profile.Error = + "You haven't specified a Bungie name to look up. If you want to use your own account, please register with '/user register' first." + + "Alternatively, you can provide a specific name to search for."; + return profile; + } + + profile.MembershipId = currentUser.DestinyMembershipId; + profile.MembershipType = currentUser.DestinyMembershipType; + profile.BungieName = currentUser.BungieName; + + return profile; + } + + var name = bungieTag.Split("#").First(); + var code = Convert.ToInt16(bungieTag.Split("#").Last()); + + var goodProfile = await BungieApiUtils.GetLatestProfileAsync(bungieClient, name, code); + if (goodProfile == null || goodProfile.MembershipType == BungieMembershipType.None) + { + profile.Error = + $"No profiles found matching `{bungieTag}`.\nThis can happen if no characters are currently on the Bungie account."; + return profile; + } + + profile.MembershipId = goodProfile.MembershipId; + profile.MembershipType = goodProfile.MembershipType; + profile.BungieName = $"{goodProfile.BungieGlobalDisplayName}#{goodProfile.BungieGlobalDisplayNameCode}"; + + return profile; + } + + public class ProfileResponse + { + public string? Error { get; set; } + public long MembershipId { get; set; } + public BungieMembershipType MembershipType { get; set; } + public string? BungieName { get; set; } + } } \ No newline at end of file diff --git a/renovate.json b/renovate.json index 39a2b6e..8b1edd8 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,6 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base" - ] -} +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ] +}