mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-19 14:55:24 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7347de58af | ||
|
|
f1ee932f23 | ||
|
|
cdbc81e310 | ||
|
|
629c6ed14f | ||
|
|
6577db54bc | ||
|
|
926e9b7b48 | ||
|
|
c8433210e3 | ||
|
|
3274405c51 | ||
|
|
01bde80c39 | ||
|
|
3f810b8a94 | ||
|
|
5d7ba2598f | ||
|
|
670d6bcbd5 | ||
|
|
9690d649fa | ||
|
|
821ce69547 | ||
|
|
4f524ada67 | ||
|
|
0c2234f31b | ||
|
|
70085efd39 | ||
|
|
bfa2128868 | ||
|
|
9b0da9b13c | ||
|
|
721ee8e494 | ||
|
|
5458db891f | ||
|
|
9d9c15d0f6 | ||
|
|
4f49fc1cdf | ||
|
|
7efc7ba698 | ||
|
|
a79a6eae98 | ||
|
|
0801256f4c | ||
|
|
e0799dd100 | ||
|
|
24f4607899 | ||
|
|
7aee0dfc16 | ||
|
|
5fcb2314bc | ||
|
|
f218b89f6c | ||
|
|
cc607b37c9 | ||
|
|
f80ea8cf0c | ||
|
|
39f6707d23 | ||
|
|
eb11029ece | ||
|
|
4583b5b2d3 | ||
|
|
8c01377667 | ||
|
|
9a130d71dd | ||
|
|
018ed6c5b5 | ||
|
|
cb48248c82 | ||
|
|
e1284375e2 | ||
|
|
d38d620a84 | ||
|
|
ce810dafab | ||
|
|
aabc98e4fc | ||
|
|
7eb0b7cc4f | ||
|
|
f1eb829ac4 | ||
|
|
4b03a5a16f | ||
|
|
71c90100be | ||
|
|
ee512d130d | ||
|
|
03d0759e57 | ||
|
|
0db7628d66 | ||
|
|
d1d1ba6c08 | ||
|
|
d16a88a9bc | ||
|
|
a9d93f4162 | ||
|
|
632b5a55ac | ||
|
|
6424505631 | ||
|
|
dfc1d3ba0a | ||
|
|
5bee88016d | ||
|
|
5a37250680 | ||
|
|
1c4ccb9fa3 | ||
|
|
8403dadca7 | ||
|
|
4ac4cb0886 | ||
|
|
74f13d2447 | ||
|
|
bf53793729 | ||
|
|
e69dbf6791 | ||
|
|
a0eafa8a13 | ||
|
|
b0a236beb4 | ||
|
|
c10b81f3a1 | ||
|
|
6cd51d6584 | ||
|
|
a283117cc8 | ||
|
|
329e64232c | ||
|
|
feb3c9042e | ||
|
|
71f15f56a4 | ||
|
|
d37951b832 | ||
|
|
908a149df4 | ||
|
|
38cf140dfa | ||
|
|
d13e1a2d08 | ||
|
|
a0c7842b84 | ||
|
|
de13b68633 | ||
|
|
f289602068 | ||
|
|
15f4ee8979 | ||
|
|
d826dea457 | ||
|
|
b89a6666a3 | ||
|
|
1dc69fd0c2 | ||
|
|
5005b07f09 | ||
|
|
0b692165e0 | ||
|
|
ffee0fdf4c | ||
|
|
72b4cd5470 | ||
|
|
dc9be53ace | ||
|
|
3a8a6b0f7f | ||
|
|
7cdd0534f6 | ||
|
|
4b14ab9312 | ||
|
|
57e1ddb8da | ||
|
|
c7609c0f7e | ||
|
|
1eca8021d2 | ||
|
|
0077f35c4d | ||
|
|
28b0a0a138 | ||
|
|
cc7ce92013 | ||
|
|
5bd02e56ee | ||
|
|
8c7cd0a562 | ||
|
|
3ab3f72366 | ||
|
|
733883a6c2 | ||
|
|
d1ed8aeaf6 | ||
|
|
66ad44b8ce | ||
|
|
18e51ae408 | ||
|
|
06940dbf38 | ||
|
|
875b29f8ba | ||
|
|
a953c3a0d3 | ||
|
|
ce198fcfc9 | ||
|
|
3d84648af2 | ||
|
|
38bb43bba3 | ||
|
|
cc00709016 | ||
|
|
ee02b3b49a | ||
|
|
d1d6b7d757 | ||
|
|
4e1c0c4f50 | ||
|
|
2a7e2c90fc | ||
|
|
0dc957a99d | ||
|
|
f3f0aeb97e | ||
|
|
d6dbe6f2cd | ||
|
|
79da1801bc | ||
|
|
2b692b2d88 | ||
|
|
a7a98f7288 | ||
|
|
5d27d9c380 | ||
|
|
fb4185b541 | ||
|
|
d2d6e87e12 | ||
|
|
354cdda109 | ||
|
|
83429e264a | ||
|
|
ffdf374cdd | ||
|
|
aed34608ee | ||
|
|
18981e131d | ||
|
|
fe0a77d89d | ||
|
|
dbfd555f0d | ||
|
|
85d4ac3a29 | ||
|
|
dcb983d3de | ||
|
|
ba1e4348ad | ||
|
|
04bc7cffc6 | ||
|
|
01b74a936b | ||
|
|
654b6bc10f | ||
|
|
c9e6b9f626 | ||
|
|
554f1aea9b | ||
|
|
6fb817855c | ||
|
|
b3f5fadfe3 | ||
|
|
9275b7a7f8 | ||
|
|
2d06ff85b8 | ||
|
|
07d06313d9 | ||
|
|
546409130c | ||
|
|
82436872f8 | ||
|
|
ad6f76af0c | ||
|
|
8f0ad91a22 | ||
|
|
6a70c5b7cc | ||
|
|
5f5d67fdf2 | ||
|
|
150b41647a | ||
|
|
66e52e7324 | ||
|
|
23328240a9 | ||
|
|
3f06e9486d | ||
|
|
52a8e912e9 | ||
|
|
641aa8250e | ||
|
|
faa47f32c7 | ||
|
|
e3dac780df | ||
|
|
dfc0f12150 | ||
|
|
638fb38fa0 | ||
|
|
4d6a06ccdf | ||
|
|
3228604876 | ||
|
|
44879924d6 | ||
|
|
6b7478f6ae | ||
|
|
f54d95c1e7 | ||
|
|
5315a45a98 | ||
|
|
8575d970a3 | ||
|
|
5c611eca4f | ||
|
|
71aa37b965 | ||
|
|
0f1b1cc83d | ||
|
|
198c1e6eb3 | ||
|
|
e7c9111a1f | ||
|
|
1191e996db | ||
|
|
19de3c99f9 | ||
|
|
d857b6dc26 | ||
|
|
68b5b79035 | ||
|
|
318032d998 | ||
|
|
483860532f | ||
|
|
694dbe82a9 | ||
|
|
a936f24e32 | ||
|
|
a2ec87ced2 | ||
|
|
48955a7dd7 | ||
|
|
9d7c6c29b0 | ||
|
|
902d210dfd | ||
|
|
57867851a9 | ||
|
|
ca82cc92bf | ||
|
|
569ce1e656 | ||
|
|
a96c6c3f66 | ||
|
|
28c3b2f8c1 | ||
|
|
deeccd81b4 | ||
|
|
6a27245ae8 | ||
|
|
6f4063abb7 | ||
|
|
f307bcd665 | ||
|
|
02ca41ba6d | ||
|
|
a0ebc87b7c | ||
|
|
d21c55deb0 | ||
|
|
50a8131ec2 | ||
|
|
e70cfa3d99 | ||
|
|
4c0c45f1c7 | ||
|
|
a9e819a83a | ||
|
|
65830f9125 | ||
|
|
3d9106addf | ||
|
|
2863032d9a | ||
|
|
aada189b1b | ||
|
|
22ea4de66e | ||
|
|
9859617a74 | ||
|
|
0629c1929d | ||
|
|
6ec45396c3 | ||
|
|
b76a9b80fb | ||
|
|
f4bc58bbf7 | ||
|
|
09fdbb6f95 | ||
|
|
8ee7ed23e4 | ||
|
|
8d8a78cf88 | ||
|
|
f0652231cb | ||
|
|
d9aa760256 | ||
|
|
a65f375255 | ||
|
|
3ee58e2711 | ||
|
|
9b3b083aec | ||
|
|
ecb9b8f172 | ||
|
|
5765c27240 | ||
|
|
c53456112a | ||
|
|
ccea21886e | ||
|
|
37be8de5ac | ||
|
|
107e43a15f | ||
|
|
17b3ed34db | ||
|
|
cce9cd34af | ||
|
|
6a80f8ee5d | ||
|
|
edb7f0d0bd | ||
|
|
8e69375338 | ||
|
|
d24ae98fb0 | ||
|
|
111b3ea632 | ||
|
|
cc1e759972 | ||
|
|
ad0527ed73 | ||
|
|
8ffbb918ea | ||
|
|
c27a0dba65 | ||
|
|
ad8305c66d | ||
|
|
29fe12f094 | ||
|
|
9dbe4c5eaf | ||
|
|
1e9aca3807 | ||
|
|
895da23f7d | ||
|
|
f788a10879 | ||
|
|
9fe4be0467 | ||
|
|
b1a7d3a111 | ||
|
|
8b9fdaaa30 | ||
|
|
60d5947535 | ||
|
|
0ba0e64a2a | ||
|
|
e1dfd1f0d0 | ||
|
|
cd2a529381 | ||
|
|
6ba8dcac49 | ||
|
|
f2e76b5459 | ||
|
|
cfbf6ed021 | ||
|
|
a372eb5125 | ||
|
|
76b89ca0e8 | ||
|
|
2c1721d52c | ||
|
|
324a77a625 | ||
|
|
88e59b8ec9 | ||
|
|
df71a17d9f | ||
|
|
8451f53e19 | ||
|
|
e795af5c11 | ||
|
|
efa3c5175c | ||
|
|
32efe42a61 | ||
|
|
97d2d09cdc | ||
|
|
ed90d567a4 | ||
|
|
51d6fb0f42 | ||
|
|
c10525708c | ||
|
|
0a69d795aa | ||
|
|
3b1d6831a5 | ||
|
|
b4c1dbcddb | ||
|
|
db5d62d7c0 | ||
|
|
ed5ccf38c6 | ||
|
|
7671e0c04c | ||
|
|
f3b8221b29 | ||
|
|
8fdc9a67c0 | ||
|
|
bb2e739876 | ||
|
|
852cbff5f3 | ||
|
|
6e1c111876 | ||
|
|
9f60839e40 | ||
|
|
dd37db18b5 | ||
|
|
793d60f7b5 | ||
|
|
08674cd7a6 | ||
|
|
dca3e39a6d | ||
|
|
8a1033d4b6 | ||
|
|
e4ebe558d7 | ||
|
|
70728cc5ed | ||
|
|
b49a0a5ff4 | ||
|
|
b48d959ffb | ||
|
|
b8e1ad89af | ||
|
|
b2bfbfcd86 | ||
|
|
062e28a6d2 | ||
|
|
dc0f833291 | ||
|
|
e598237916 | ||
|
|
6b96d3d9e9 | ||
|
|
1dbb610846 | ||
|
|
5c649b0c15 | ||
|
|
527ab041d9 | ||
|
|
ff94e90259 | ||
|
|
51efbcce1e | ||
|
|
87b2345105 | ||
|
|
5022d33ca9 | ||
|
|
141f949a63 | ||
|
|
3913c71fd8 | ||
|
|
5706652c40 | ||
|
|
768b6b20f5 | ||
|
|
7066b7dbb6 | ||
|
|
17e01fc7b9 | ||
|
|
ee9fcf38b7 | ||
|
|
5abb24bdd4 | ||
|
|
53f17d3f22 | ||
|
|
b728c38dc1 | ||
|
|
5e57b6ecd0 | ||
|
|
e9ffcdf7c3 | ||
|
|
118657de7c | ||
|
|
34c332504b | ||
|
|
d7a29d68a1 | ||
|
|
eefa02837d | ||
|
|
5b2812fa61 | ||
|
|
e3ddfb88c1 | ||
|
|
664d94aeaa | ||
|
|
e2baf63099 | ||
|
|
c1b7000139 | ||
|
|
6e8333d76f | ||
|
|
c67eddc9d4 | ||
|
|
292cf6fd94 | ||
|
|
69038bca43 | ||
|
|
f05d15ce36 | ||
|
|
98cb349d67 | ||
|
|
a4314ee4d5 | ||
|
|
96097bd25a | ||
|
|
14029e6af2 | ||
|
|
365777141d | ||
|
|
aaa5da8d9b | ||
|
|
b898ab5679 | ||
|
|
b896fa5cc7 |
+77
-17
@@ -12,6 +12,7 @@ on:
|
||||
paths:
|
||||
- "Daybreak/**"
|
||||
- "Daybreak.Installer/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -19,7 +20,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x64]
|
||||
targetplatform: [x86]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -32,7 +33,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -45,20 +46,18 @@ jobs:
|
||||
run: |
|
||||
$changeLog = git log --no-merges --pretty="%h - %s (%an)<br />" ${{ env.LatestReleaseTag }}..HEAD
|
||||
echo "::set-env name=Changelog::$changeLog"
|
||||
mkdir Publish
|
||||
echo $changeLog > .\Publish\changelog.txt
|
||||
env:
|
||||
LatestReleaseTag: ${{steps.getLatestTag.outputs.tag}}
|
||||
|
||||
- name: Print changelog
|
||||
run: |
|
||||
echo "${{ env.Changelog }}"
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '7.x'
|
||||
dotnet-version: '9.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1
|
||||
uses: microsoft/setup-msbuild@v2.0.0
|
||||
|
||||
- name: Setup project secrets
|
||||
run: |
|
||||
@@ -66,12 +65,12 @@ jobs:
|
||||
dotnet user-secrets --project Daybreak\Daybreak.csproj set AadTenantId "${{ secrets.AadTenantId }}"
|
||||
|
||||
- name: Restore project
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier --property:SolutionDir=$GITHUB_WORKSPACE
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration
|
||||
run: dotnet build Daybreak -c $env:Configuration --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
|
||||
- name: Set version variable
|
||||
run: |
|
||||
@@ -79,12 +78,22 @@ jobs:
|
||||
echo "::set-env name=Version::$version"
|
||||
|
||||
- name: Create publish launcher files
|
||||
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=false --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish installer files
|
||||
run: dotnet publish .\Daybreak.Installer\Daybreak.Installer.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
run: dotnet publish .\Daybreak.Installer\Daybreak.Installer.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish extractor files
|
||||
run: dotnet publish .\Daybreak.7ZipExtractor\Daybreak.7ZipExtractor.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=false --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish API files
|
||||
run: dotnet publish .\Daybreak.API\Daybreak.API.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishSingleFile=false --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
@@ -94,16 +103,67 @@ jobs:
|
||||
.\Scripts\BuildRelease.ps1 -version $env:Version
|
||||
shell: pwsh
|
||||
|
||||
- name: Publish release
|
||||
uses: Xotl/cool-github-releases@v1.1.8
|
||||
- name: Submit virustotal scan
|
||||
shell: pwsh
|
||||
run: |
|
||||
cd Publish
|
||||
$apiKey = "${{ secrets.VIRUSTOTAL_APIKEY }}"
|
||||
$archiveName = "daybreakv${{ env.Version }}.zip"
|
||||
$uploadUrlResponse = curl https://www.virustotal.com/api/v3/files/upload_url -H x-apikey:"$apiKey"
|
||||
$uploadUrlResponse
|
||||
$uploadUrlJson = $uploadUrlResponse | ConvertFrom-Json
|
||||
$uploadUrl = $uploadUrlJson.data
|
||||
$uploadResponse = curl --request POST --header x-apikey:"$apiKey" --header 'content-type: multipart/form-data' --form file="@$archiveName" --url $uploadUrl
|
||||
$uploadResponse
|
||||
$uploadResponseJson = $uploadResponse | ConvertFrom-Json
|
||||
$resultsUrl = "https://www.virustotal.com/api/v3/analyses/$($uploadResponseJson.data.id)"
|
||||
$resultsUrl
|
||||
# Poll the results until the status is "completed"
|
||||
$status = ""
|
||||
while ($status -ne "completed") {
|
||||
Start-Sleep -Seconds 10 # Wait for 10 seconds between checks
|
||||
$results = curl --header x-apikey:"$apiKey" --url $resultsUrl
|
||||
$results
|
||||
$resultsJson = $results | ConvertFrom-Json
|
||||
$status = $resultsJson.data.attributes.status
|
||||
Write-Host "Current status: $status"
|
||||
}
|
||||
|
||||
$resultsJson.data.attributes.results | ConvertTo-Json | Out-File -FilePath "VirusTotal.Results.json" -Encoding UTF8
|
||||
$resultsJson.data.attributes.stats | ConvertTo-Json | Out-File -FilePath "VirusTotal.Stats.json" -Encoding UTF8
|
||||
$stats = $resultsJson.data.attributes.stats
|
||||
echo "::set-env name=VirusTotalStats::$stats"
|
||||
|
||||
- name: Publish blob files
|
||||
run: |
|
||||
Write-Host $env
|
||||
.\Scripts\PushFilesToBlobStorage.ps1 -version $env:Version -sourcePath .\Publish\ -connectionString "${{ secrets.BLOBSTORAGE_CONNECTIONSTRING }}"
|
||||
shell: pwsh
|
||||
|
||||
- name: Create release draft
|
||||
uses: Xotl/cool-github-releases@v1.1.10
|
||||
with:
|
||||
mode: update
|
||||
tag_name: v${{ env.Version }}
|
||||
release_name: Daybreak v${{ env.Version }}
|
||||
assets: .\Publish\daybreakv${{ env.Version }}.zip
|
||||
assets: .\Publish\daybreakv${{ env.Version }}.zip;.\Publish\VirusTotal.Results.json;.\Publish\VirusTotal.Stats.json
|
||||
github_token: ${{ env.GITHUB_TOKEN }}
|
||||
replace_assets: true
|
||||
body_mrkdwn: ${{ env.Changelog }}
|
||||
body_mrkdwn: |
|
||||
${{ env.Changelog }}
|
||||
|
||||
** VirustTotal Stats: **
|
||||
```
|
||||
${{ env.VirusTotalStats }}
|
||||
```
|
||||
isDraft: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Publish release
|
||||
run: |
|
||||
gh release edit v${{ env.Version }} --draft=false
|
||||
shell: powershell
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -19,35 +19,35 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x64]
|
||||
targetplatform: [x86]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreal.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreak.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '7.x'
|
||||
dotnet-version: '9.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1
|
||||
uses: microsoft/setup-msbuild@v2.0.0
|
||||
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path
|
||||
|
||||
run: dotnet test $env:Test_Project_Path --property:SolutionDir=$env:GITHUB_WORKSPACE -p:ParallelizeTestCollections=false
|
||||
|
||||
- name: Restore the Wpf application to populate the obj folder
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
env:
|
||||
Configuration: Debug
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
@@ -36,13 +36,22 @@ jobs:
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
env:
|
||||
Configuration: Release
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreak.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -57,12 +66,12 @@ jobs:
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '6.x'
|
||||
dotnet-version: '9.x'
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
#- name: Autobuild
|
||||
# uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -74,5 +83,8 @@ jobs:
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x64]
|
||||
targetplatform: [x86]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -25,16 +25,21 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.x'
|
||||
|
||||
- name: Get Latest Tag
|
||||
id: getLatestTag
|
||||
uses: WyriHaximus/github-action-get-previous-tag@v1
|
||||
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration
|
||||
run: dotnet build Daybreak -c $env:Configuration --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
|
||||
- name: Set version variable
|
||||
run: |
|
||||
|
||||
+4
-1
@@ -28,6 +28,7 @@ x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
@@ -361,4 +362,6 @@ MigrationBackup/
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
FodyWeavers.xsd
|
||||
|
||||
.idea
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RootNamespace>Daybreak._7ZipExtractor</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpCompress" Version="0.39.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Extractor is in a different executable because of memory limitations. Daybreak needs to be compiled for x86 and as such has a memory limit of 2GB.
|
||||
* 7Zip algorithm may require more than 2GB memory to unpack large zip files.
|
||||
* As such, Daybreak.7ZipExtractor is x64.
|
||||
*/
|
||||
using SharpCompress.Archives;
|
||||
|
||||
if (args.Length != 2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var archivePath = args[0];
|
||||
var destinationDirectory = args[1];
|
||||
|
||||
using var fileStream = new FileStream(archivePath, FileMode.Open);
|
||||
using var archive = ArchiveFactory.Open(fileStream);
|
||||
var progress = 0d;
|
||||
var count = archive.Entries.Count();
|
||||
var reader = archive.ExtractAllEntries();
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
var entry = reader.Entry;
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
var directoryName = Path.Combine(Path.GetFullPath(destinationDirectory), entry.Key);
|
||||
Directory.CreateDirectory(directoryName);
|
||||
continue;
|
||||
}
|
||||
|
||||
var fileName = Path.Combine(Path.GetFullPath(destinationDirectory), entry.Key);
|
||||
using var entryStream = new FileStream(fileName, FileMode.Create);
|
||||
using (var stream = reader.OpenEntryStream())
|
||||
{
|
||||
stream.CopyTo(entryStream);
|
||||
}
|
||||
|
||||
progress += 1d / count;
|
||||
Console.WriteLine($"{progress} {fileName}");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -0,0 +1,13 @@
|
||||
using Net.Sdk.Web;
|
||||
|
||||
namespace Daybreak.API.Controllers;
|
||||
|
||||
[GenerateController("api/test")]
|
||||
public sealed class TestController
|
||||
{
|
||||
[GenerateGet("testing")]
|
||||
public IResult GetTest(CancellationToken token)
|
||||
{
|
||||
return Results.Text("Hello from injected ASP-NET Core!", "text/plain");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<StripSymbols>true</StripSymbols>
|
||||
<InteropExports>true</InteropExports>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<PublishAot>true</PublishAot>
|
||||
<SelfContained>true</SelfContained>
|
||||
|
||||
|
||||
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
|
||||
<UseAppHost>false</UseAppHost>
|
||||
<EnableIISSupport>false</EnableIISSupport>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Net.Sdk.Web.Extensions.SourceGenerators" Version="0.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Daybreak.Shared\Daybreak.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DaybreakHostOutputDir>$(MSBuildProjectDirectory)\..\Daybreak\bin\x86\$(Configuration)\$(TargetFramework)\</DaybreakHostOutputDir>
|
||||
<ShouldPublishAot>true</ShouldPublishAot>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PublishIntoDaybreak" AfterTargets="PostBuild" Condition="'$(ShouldPublishAot)'=='true'">
|
||||
<Message Text="📦 dotnet-publish Daybreak.API → $(DaybreakHostOutputDir)" Importance="High" />
|
||||
|
||||
<Exec Command="dotnet publish "$(MSBuildProjectFullPath)" -c $(Configuration) -r win-x86 --self-contained true -o "$(DaybreakHostOutputDir)"" WorkingDirectory="$(ProjectDir)" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.InteropServices;
|
||||
using Daybreak.API.Extensions;
|
||||
using Daybreak.API.Serialization;
|
||||
using Net.Sdk.Web;
|
||||
|
||||
namespace Daybreak.API;
|
||||
|
||||
public static class EntryPoint
|
||||
{
|
||||
private const int StartPort = 5080;
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "ThreadInit"), STAThread]
|
||||
public static int ThreadInit(IntPtr _, int __)
|
||||
{
|
||||
ConsoleExtensions.AllocateAnsiConsole();
|
||||
var port = FindAvailablePort(StartPort);
|
||||
if (port <= 0)
|
||||
{
|
||||
Console.WriteLine($"No available port found starting from {StartPort}");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Starting Daybreak API on port {port}");
|
||||
Task.Run(() => StartServer(port));
|
||||
return port;
|
||||
}
|
||||
|
||||
private static async Task StartServer(int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.WebHost.UseUrls($"http://127.0.0.1:{port}");
|
||||
builder.Services.ConfigureHttpJsonOptions(options =>
|
||||
{
|
||||
options.SerializerOptions.TypeInfoResolverChain.Insert(0, new ApiJsonSerializerContext());
|
||||
});
|
||||
builder.Logging.AddConsole();
|
||||
builder.WithRoutes();
|
||||
|
||||
var app = builder.Build();
|
||||
app.UseRoutes();
|
||||
|
||||
await app.RunAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static int FindAvailablePort(int startPort)
|
||||
{
|
||||
var port = startPort;
|
||||
while (!IsPortAvailable(port))
|
||||
{
|
||||
port++;
|
||||
if (port > 65535 || port < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
private static bool IsPortAvailable(int port)
|
||||
{
|
||||
var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
|
||||
var tcpListeners = ipProperties.GetActiveTcpListeners();
|
||||
if (tcpListeners.Any(endpoint => endpoint.Port == port))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var tcpConnections = ipProperties.GetActiveTcpConnections();
|
||||
if (tcpConnections.Any(conn => conn.LocalEndPoint.Port == port))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Daybreak.API.Extensions;
|
||||
|
||||
public static class ConsoleExtensions
|
||||
{
|
||||
public static void AllocateAnsiConsole()
|
||||
{
|
||||
NativeMethods.AllocConsole();
|
||||
var handle = NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE);
|
||||
if (!NativeMethods.GetConsoleMode(handle, out var mode))
|
||||
{
|
||||
Console.WriteLine("Failed to get console mode");
|
||||
}
|
||||
|
||||
if (!NativeMethods.SetConsoleMode(handle, mode | NativeMethods.ENABLE_VIRTUAL_TERMINAL_PROCESSING | NativeMethods.ENABLE_PROCESSED_OUTPUT))
|
||||
{
|
||||
Console.WriteLine("Failed to enable virtual terminal processing");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Daybreak.API;
|
||||
|
||||
internal static partial class NativeMethods
|
||||
{
|
||||
public const int STD_OUTPUT_HANDLE = -11;
|
||||
public const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
|
||||
public const uint ENABLE_PROCESSED_OUTPUT = 0x0001;
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool AllocConsole();
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
public static partial nint GetConsoleWindow();
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
public static partial nint GetStdHandle(int nStdHandle);
|
||||
|
||||
[LibraryImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool GetConsoleMode(nint hConsoleHandle, out uint lpMode);
|
||||
|
||||
[LibraryImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool SetConsoleMode(nint hConsoleHandle, uint dwMode);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Daybreak.API": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:51249;http://localhost:51250"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Daybreak.API.Serialization;
|
||||
|
||||
[JsonSerializable(typeof(string))]
|
||||
public partial class ApiJsonSerializerContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<PublishSingleFile>True</PublishSingleFile>
|
||||
<Self-Contained>True</Self-Contained>
|
||||
<PublishReadyToRun>True</PublishReadyToRun>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,59 +1,116 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
|
||||
static void RenderProgressBar(int currentStep, int totalSteps, int barSize)
|
||||
{
|
||||
Console.CursorLeft = 0; // Reset cursor position to the start of the line
|
||||
Console.Write("["); // Start of the progress bar
|
||||
|
||||
double pctComplete = (double)currentStep / totalSteps;
|
||||
int chars = (int)Math.Round(pctComplete * barSize);
|
||||
|
||||
Console.Write(new string('=', chars)); // The 'completed' part of the bar
|
||||
Console.Write(new string(' ', barSize - chars)); // The 'remaining' part of the bar
|
||||
|
||||
Console.Write("] ");
|
||||
Console.Write($"{pctComplete:P0}"); // Display the percentage completed
|
||||
}
|
||||
|
||||
const string tempFile = "tempfile.zip";
|
||||
const string updatePkg = "update.pkg";
|
||||
const string executableName = "Daybreak.exe";
|
||||
Console.Title = "Daybreak Installer";
|
||||
Console.WriteLine("Starting installation...");
|
||||
if (File.Exists(tempFile) is false)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("Unable to find launcher package. Aborting installation");
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
|
||||
while (Process.GetProcesses().Where(p => p.ProcessName == "Daybreak").FirstOrDefault()?.HasExited is false)
|
||||
{
|
||||
Console.WriteLine($"Detected Daybreak process is still running. Waiting 5s and retrying");
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
|
||||
Console.WriteLine("Unpacking files...");
|
||||
try
|
||||
{
|
||||
ZipFile.ExtractToDirectory(tempFile, AppContext.BaseDirectory, true);
|
||||
}
|
||||
catch
|
||||
if (File.Exists(updatePkg))
|
||||
{
|
||||
Console.WriteLine("Unpacking files...");
|
||||
|
||||
}
|
||||
using var fileStream = new FileStream(updatePkg, FileMode.Open);
|
||||
var sizeBuffer = new byte[4];
|
||||
var copyBuffer = new byte[1024];
|
||||
while (fileStream.Position < fileStream.Length - 1)
|
||||
{
|
||||
/*
|
||||
* For each file downloaded, we write to the package the following:
|
||||
* Size of the name string
|
||||
* UTF-8 encoded name string
|
||||
* Size of the relative path string
|
||||
* UTF-8 encoded relative path string
|
||||
* Size of the binary
|
||||
* Binary data
|
||||
*/
|
||||
|
||||
Console.WriteLine("Deleting browser caches");
|
||||
try
|
||||
{
|
||||
Directory.Delete("BrowserData", true);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
Directory.Delete("Daybreak.exe.WebView2", true);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
}
|
||||
await fileStream.ReadAsync(sizeBuffer, 0, 4);
|
||||
var fileNameSize = BitConverter.ToInt32(sizeBuffer, 0);
|
||||
var fileNameBuffer = new byte[fileNameSize];
|
||||
await fileStream.ReadAsync(fileNameBuffer, 0, fileNameSize);
|
||||
var fileName = Encoding.UTF8.GetString(fileNameBuffer);
|
||||
|
||||
Console.WriteLine("Deleting package");
|
||||
try
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
RenderProgressBar((int)fileStream.Position, (int)fileStream.Length, 40);
|
||||
|
||||
await fileStream.ReadAsync(sizeBuffer, 0, 4);
|
||||
var relativePathSize = BitConverter.ToInt32(sizeBuffer, 0);
|
||||
var relativePathBuffer = new byte[relativePathSize];
|
||||
await fileStream.ReadAsync(relativePathBuffer, 0, relativePathSize);
|
||||
var relativePath = Encoding.UTF8.GetString(relativePathBuffer);
|
||||
|
||||
RenderProgressBar((int)fileStream.Position, (int)fileStream.Length, 40);
|
||||
|
||||
await fileStream.ReadAsync(sizeBuffer, 0, 4);
|
||||
var binarySize = BitConverter.ToInt32(sizeBuffer, 0);
|
||||
var fileInfo = new FileInfo(relativePath);
|
||||
fileInfo.Directory!.Create();
|
||||
using var destinationStream = new FileStream(relativePath, FileMode.Create);
|
||||
while(binarySize > 0)
|
||||
{
|
||||
var toRead = Math.Min(binarySize, copyBuffer.Length);
|
||||
await fileStream.ReadAsync(copyBuffer, 0, toRead);
|
||||
await destinationStream.WriteAsync(copyBuffer, 0, toRead);
|
||||
binarySize -= toRead;
|
||||
|
||||
RenderProgressBar((int)fileStream.Position, (int)fileStream.Length, 40);
|
||||
}
|
||||
}
|
||||
|
||||
fileStream.Close();
|
||||
fileStream.Dispose();
|
||||
File.Delete(updatePkg);
|
||||
}
|
||||
catch (Exception e)
|
||||
else if (File.Exists(tempFile))
|
||||
{
|
||||
Console.WriteLine($"Failed to delete {tempFile}.\n{e}");
|
||||
Console.WriteLine("Unpacking files...");
|
||||
try
|
||||
{
|
||||
ZipFile.ExtractToDirectory(tempFile, AppContext.BaseDirectory, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Console.WriteLine("Deleting package");
|
||||
try
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Failed to delete {tempFile}.\n{e}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("Unable to find launcher package. Aborting installation");
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Launching application");
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Configuration.Options;
|
||||
namespace Daybreak.Shared.Configuration.Options;
|
||||
|
||||
public interface ITradeChatOptions
|
||||
{
|
||||
@@ -0,0 +1,51 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class AttributeJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Models.Guildwars.Attribute)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Models.Guildwars.Attribute.TryParse(name, out var namedAttribute))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedAttribute;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Models.Guildwars.Attribute.TryParse((int)id.Value, out var parsedAttribute))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedAttribute;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Models.Guildwars.Attribute attribute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(attribute.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media.Effects;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class BooleanToEffectConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not bool boolean)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
if (parameter is not Effect effect)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
if (!boolean)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class BooleanToGridLengthConverter : IValueConverter
|
||||
{
|
||||
+3
-3
@@ -4,7 +4,7 @@ using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class BooleanToVisibilityConverter : IValueConverter
|
||||
{
|
||||
@@ -38,12 +38,12 @@ public class BooleanToVisibilityConverter : IValueConverter
|
||||
}
|
||||
|
||||
var objValue = value.Cast<bool>();
|
||||
if ((objValue && this.TriggerValue && this.IsHidden) || (!objValue && !this.TriggerValue && this.IsHidden))
|
||||
if (objValue && this.TriggerValue && this.IsHidden || !objValue && !this.TriggerValue && this.IsHidden)
|
||||
{
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
|
||||
if ((objValue && this.TriggerValue && !this.IsHidden) || (!objValue && !this.TriggerValue && !this.IsHidden))
|
||||
if (objValue && this.TriggerValue && !this.IsHidden || !objValue && !this.TriggerValue && !this.IsHidden)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class CampaignJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Campaign)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Campaign.TryParse(name, out var namedCampaign))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedCampaign;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Campaign.TryParse((int)id.Value, out var parsedCampaign))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedCampaign;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Campaign campaign)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(campaign.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ContinentJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Continent)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Continent.TryParse(name, out var namedContinent))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedContinent;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Continent.TryParse((int)id.Value, out var parsedContinent))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedContinent;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Continent continent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(continent.Id);
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -2,9 +2,10 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class DateTimeConverter : IValueConverter
|
||||
{
|
||||
public string? Format { get; set; }
|
||||
public bool LongTime { get; set; }
|
||||
public bool LongDate { get; set; }
|
||||
|
||||
@@ -15,6 +16,11 @@ public sealed class DateTimeConverter : IValueConverter
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (this.Format is not null)
|
||||
{
|
||||
return dateTime.ToString(this.Format);
|
||||
}
|
||||
|
||||
if (this.LongTime)
|
||||
{
|
||||
return dateTime.ToLongTimeString();
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class DoubleMultiplierConverter : IValueConverter
|
||||
{
|
||||
public double Multiplier { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not double d)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return d * this.Multiplier;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class EqualityToVisibilityConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values.Length != 2)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
return values[0] == values[1] ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using Daybreak.Shared;
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Daybreak.Shared.Services.Events;
|
||||
using ExCSS;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class EventCalendarDayToBrushConverter : IValueConverter
|
||||
{
|
||||
private readonly EventToBrushConverter eventToBrushConverter = new();
|
||||
private readonly IEventService eventService = Global.GlobalServiceProvider.GetRequiredService<IEventService>();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not DateTime dayDate)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name}");
|
||||
}
|
||||
|
||||
dayDate = new DateTime(dayDate.Year, dayDate.Month, dayDate.Day, 19, 0, 0);
|
||||
var activeEvents = this.eventService.GetActiveEvents(dayDate).ToList();
|
||||
if (activeEvents.Count == 0)
|
||||
{
|
||||
return Brushes.Transparent;
|
||||
}
|
||||
|
||||
if (activeEvents.Count == 1 &&
|
||||
activeEvents.FirstOrDefault() is Event ev)
|
||||
{
|
||||
return this.eventToBrushConverter.Convert(ev, typeof(Brush), parameter, culture);
|
||||
}
|
||||
|
||||
var brushes = this.eventService.GetActiveEvents(dayDate).Select(e => this.eventToBrushConverter.Convert(e, typeof(Brush), parameter, culture)).OfType<SolidColorBrush>().ToList();
|
||||
var canvas = new Canvas();
|
||||
double width = 1.0 / brushes.Count; // Assuming a normalized width for each color segment
|
||||
|
||||
for (int i = 0; i < brushes.Count; i++)
|
||||
{
|
||||
var rect = new Rectangle
|
||||
{
|
||||
Width = width,
|
||||
Height = 1,
|
||||
Fill = brushes[i],
|
||||
RenderTransform = new TranslateTransform(i * width, 0)
|
||||
};
|
||||
canvas.Children.Add(rect);
|
||||
}
|
||||
|
||||
return new VisualBrush
|
||||
{
|
||||
Visual = canvas,
|
||||
Stretch = Stretch.None,
|
||||
TileMode = TileMode.None,
|
||||
Viewbox = new Rect(0, 0, 1, 1),
|
||||
ViewboxUnits = BrushMappingMode.RelativeToBoundingBox,
|
||||
Transform = new RotateTransform(45, 0.5, 0.5)
|
||||
};
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Daybreak.Shared.Models;
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using Brush = System.Windows.Media.Brush;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class EventToBrushConverter : IValueConverter
|
||||
{
|
||||
private static readonly Dictionary<Event, Brush> EventMapping = new()
|
||||
{
|
||||
{ Event.CanthanNewYear, new SolidColorBrush(ColorPalette.Amber) },
|
||||
{ Event.LuckyTreatsWeek, new SolidColorBrush(ColorPalette.Green) },
|
||||
{ Event.AprilFoolsDay, new SolidColorBrush(ColorPalette.DeepPurple) },
|
||||
{ Event.SweetTreatsWeek, new SolidColorBrush(ColorPalette.Indigo) },
|
||||
{ Event.AnniversaryCelebration, new SolidColorBrush(ColorPalette.Yellow) },
|
||||
{ Event.DragonFestival, new SolidColorBrush(ColorPalette.DeepOrange) },
|
||||
{ Event.WintersdayInJuly, new SolidColorBrush(ColorPalette.LightBlue) },
|
||||
{ Event.WayfarersReverie, new SolidColorBrush(ColorPalette.Magenta) },
|
||||
{ Event.PirateWeek, new SolidColorBrush(ColorPalette.Gold) },
|
||||
{ Event.BreastCancerAwarenessMonth, new SolidColorBrush(ColorPalette.Pink) },
|
||||
{ Event.Halloween, new SolidColorBrush(ColorPalette.Orange) },
|
||||
{ Event.SpecialTreatsWeek, new SolidColorBrush(ColorPalette.Lime) },
|
||||
{ Event.WintersdayJanuary, new SolidColorBrush(ColorPalette.BlueGrey) },
|
||||
{ Event.WintersdayDecember, new SolidColorBrush(ColorPalette.BlueGrey) }
|
||||
};
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not Event e ||
|
||||
targetType != typeof(Brush))
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name} to {targetType.Name}");
|
||||
}
|
||||
|
||||
return EventMapping[e];
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class HiddenWhenNull : IValueConverter
|
||||
{
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class IntToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(string) &&
|
||||
value is int i)
|
||||
{
|
||||
return i.ToString();
|
||||
}
|
||||
else if(targetType == typeof(int) &&
|
||||
value is string s)
|
||||
{
|
||||
return int.Parse(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name} to {targetType.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(string) &&
|
||||
value is int i)
|
||||
{
|
||||
return i.ToString();
|
||||
}
|
||||
else if (targetType == typeof(int) &&
|
||||
value is string s)
|
||||
{
|
||||
return int.Parse(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name} to {targetType.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class InverseBooleanConverter : IValueConverter
|
||||
{
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ItemBaseJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(ItemBase)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is not string ||
|
||||
!ItemBase.TryParse(name, out var namedItem))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedItem;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!ItemBase.TryParse((int)id.Value, null, out var parsedItem))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedItem;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not ItemBase itemBase)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(itemBase.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ItemBaseToIntConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is int i)
|
||||
{
|
||||
return ItemBase.Parse(i, modifiers: null);
|
||||
}
|
||||
else if(value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Id;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is int i)
|
||||
{
|
||||
return ItemBase.Parse(i, modifiers: null);
|
||||
}
|
||||
else if (value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Id;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ItemBaseToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string s)
|
||||
{
|
||||
return ItemBase.Parse(s);
|
||||
}
|
||||
else if(value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Name ?? string.Empty;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string s)
|
||||
{
|
||||
return ItemBase.Parse(s);
|
||||
}
|
||||
else if (value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Name ?? string.Empty;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class MapJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Map)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Map.TryParse(name, out var namedMap))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedMap;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Map.TryParse((int)id.Value, out var parsedMap))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedMap;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Map map)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(map.Id);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class MenuButtonHighlightConverter : IValueConverter
|
||||
{
|
||||
@@ -0,0 +1,53 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class NpcJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Npc)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Npc.TryParse(name, out var namedNpc))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedNpc;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Npc.TryParse((int)id.Value, out var parsedNpc))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedNpc;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Npc npc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(npc.Ids.FirstOrDefault());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class PriceToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType != typeof(string))
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert to {targetType.Name}");
|
||||
}
|
||||
|
||||
var price = value switch
|
||||
{
|
||||
byte byteVal => byteVal,
|
||||
short shortVal => shortVal,
|
||||
ushort ushortVal => ushortVal,
|
||||
int intVal => intVal,
|
||||
uint uintVal => uintVal,
|
||||
long longVal => longVal,
|
||||
ulong ulongVal => ulongVal,
|
||||
decimal decimalVal => (double)decimalVal,
|
||||
float floatVal => (double)floatVal,
|
||||
double doubleVal => (double)doubleVal,
|
||||
_ => throw new InvalidOperationException($"Unable to convert from {value.GetType().Name}")
|
||||
};
|
||||
|
||||
var suffix = 'g';
|
||||
if (price > 1000)
|
||||
{
|
||||
price /= 1000;
|
||||
suffix = 'k';
|
||||
}
|
||||
|
||||
return $"{price}{suffix}";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ProfessionJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Profession)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Profession.TryParse(name, out var namedProfession))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedProfession;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Profession.TryParse((int)id.Value, out var parsedProfession))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedProfession;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Profession profession)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(profession.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class QuestJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Quest)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Quest.TryParse(name, out var namedQuest))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedQuest;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Quest.TryParse((int)id.Value, out var parsedQuest))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedQuest;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Quest quest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(quest.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class RegionJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Region)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Region.TryParse(name, out var namedRegion))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedRegion;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Region.TryParse((int)id.Value, out var parsedRegion))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedRegion;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Region region)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(region.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class SkillJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Skill)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Skill.TryParse(name, out var namedSkill))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedSkill;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Skill.TryParse((int)id.Value, out var parsedSkill))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedSkill;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Skill skill)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(skill.Id);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class TileButtonHighlightConverter : IValueConverter
|
||||
{
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class TimeSinceDateTimeConverter : IValueConverter
|
||||
{
|
||||
@@ -101,6 +101,6 @@ public sealed class TimeSinceDateTimeConverter : IValueConverter
|
||||
currentYear--;
|
||||
}
|
||||
|
||||
return $"{yearCount} years{(yearCount > 1 ? PluralAppend : string.Empty)} ago";
|
||||
return $"{yearCount} year{(yearCount > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class TimespanToETAConverter : IValueConverter
|
||||
{
|
||||
private const char PluralAppend = 's';
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return GetETAString(value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static string GetETAString(object obj)
|
||||
{
|
||||
if (obj is not TimeSpan timeSpan)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if ((int)timeSpan.TotalDays > 0)
|
||||
{
|
||||
return $"{(int)timeSpan.TotalDays} day{((int)timeSpan.TotalDays > 1 ? PluralAppend : string.Empty)} remaining";
|
||||
}
|
||||
|
||||
return $"{timeSpan.Hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2} remaining";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class TitleJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Title)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Title.TryParse(name, out var namedTitle))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedTitle;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Title.TryParse((int)id.Value, out var parsedTitle))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedTitle;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Title title)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(title.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Daybreak.Shared.Models.Trade;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class TradeAlertConverter : JsonConverter<ITradeAlert>
|
||||
{
|
||||
public override ITradeAlert? ReadJson(JsonReader reader, Type objectType, ITradeAlert? existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jObject = JObject.Load(reader).ToObject<dynamic>();
|
||||
if (jObject is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to deserialize {nameof(ITradeAlert)}");
|
||||
}
|
||||
|
||||
if (jObject[nameof(TradeAlert.MessageCheck)] is null)
|
||||
{
|
||||
return new QuoteAlert
|
||||
{
|
||||
Name = jObject[nameof(QuoteAlert.Name)],
|
||||
Id = jObject[nameof(QuoteAlert.Id)],
|
||||
Enabled = jObject[nameof(QuoteAlert.Enabled)],
|
||||
UpperPriceTarget = jObject[nameof(QuoteAlert.UpperPriceTarget)],
|
||||
LowerPriceTarget = jObject[nameof(QuoteAlert.LowerPriceTarget)],
|
||||
UpperPriceTargetEnabled = jObject[nameof(QuoteAlert.UpperPriceTargetEnabled)],
|
||||
LowerPriceTargetEnabled = jObject[nameof(QuoteAlert.LowerPriceTargetEnabled)],
|
||||
ItemId = jObject[nameof(QuoteAlert.ItemId)]
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TradeAlert
|
||||
{
|
||||
Name = jObject[nameof(TradeAlert.Name)],
|
||||
Id = jObject[nameof(TradeAlert.Id)],
|
||||
Enabled = jObject[nameof(TradeAlert.Enabled)],
|
||||
MessageCheck = jObject[nameof(TradeAlert.MessageCheck)],
|
||||
MessageRegexCheck = jObject[nameof(TradeAlert.MessageRegexCheck)],
|
||||
SenderCheck = jObject[nameof(TradeAlert.SenderCheck)],
|
||||
SenderRegexCheck = jObject[nameof(TradeAlert.SenderRegexCheck)]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, ITradeAlert? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
serializer.Serialize(writer, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var jObject = new JObject();
|
||||
jObject[nameof(ITradeAlert.Name)] = value.Name;
|
||||
jObject[nameof(ITradeAlert.Enabled)] = value.Enabled;
|
||||
jObject[nameof(ITradeAlert.Id)] = value.Id;
|
||||
if (value is TradeAlert tradeAlert)
|
||||
{
|
||||
jObject[nameof(TradeAlert.MessageCheck)] = tradeAlert.MessageCheck;
|
||||
jObject[nameof(TradeAlert.MessageRegexCheck)] = tradeAlert.MessageRegexCheck;
|
||||
jObject[nameof(TradeAlert.SenderCheck)] = tradeAlert.SenderCheck;
|
||||
jObject[nameof(TradeAlert.SenderRegexCheck)] = tradeAlert.SenderRegexCheck;
|
||||
}
|
||||
else if (value is QuoteAlert quoteAlert)
|
||||
{
|
||||
jObject[nameof(QuoteAlert.TraderQuoteType)] = quoteAlert.TraderQuoteType.ToString();
|
||||
jObject[nameof(QuoteAlert.ItemId)] = quoteAlert.ItemId;
|
||||
jObject[nameof(QuoteAlert.UpperPriceTarget)] = quoteAlert.UpperPriceTarget;
|
||||
jObject[nameof(QuoteAlert.UpperPriceTargetEnabled)] = quoteAlert.UpperPriceTargetEnabled;
|
||||
jObject[nameof(QuoteAlert.LowerPriceTarget)] = quoteAlert.LowerPriceTarget;
|
||||
jObject[nameof(QuoteAlert.LowerPriceTargetEnabled)] = quoteAlert.LowerPriceTargetEnabled;
|
||||
}
|
||||
|
||||
serializer.Serialize(writer, jObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Daybreak.Shared.Models.Trade;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class TraderQuoteTypeToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType != typeof(string))
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {nameof(TraderQuoteType)} to {targetType.Name}");
|
||||
}
|
||||
|
||||
return value?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not string s)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert to {targetType.Name}");
|
||||
}
|
||||
|
||||
if (!Enum.TryParse<TraderQuoteType>(s, out var enumValue))
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid string value provided {s}");
|
||||
}
|
||||
|
||||
return enumValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AvalonEdit" Version="6.3.1.120" />
|
||||
<PackageReference Include="DiffPlex" Version="1.7.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
|
||||
<PackageReference Include="ini-parser-netstandard" Version="2.5.3" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc2" />
|
||||
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3240.44" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
|
||||
<PackageReference Include="NAudio" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="PeNet" Version="5.1.0" />
|
||||
<PackageReference Include="Plumsy" Version="1.1.0" />
|
||||
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageReference Include="Slim" Version="1.9.2" />
|
||||
<PackageReference Include="Squealify" Version="0.8.2.2" />
|
||||
<PackageReference Include="Svg" Version="3.4.7" />
|
||||
<PackageReference Include="System.Formats.Asn1" Version="9.0.5" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="9.0.5" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.5" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageReference Include="SystemExtensions.NetCore" Version="1.6.11" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.6.11" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard.DependencyInjection" Version="1.6.9" />
|
||||
<PackageReference Include="WpfExtended" Version="0.7.9" />
|
||||
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.3.0" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="2.1.1" />
|
||||
<PackageReference Include="WriteableBitmapEx" Version="1.6.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
|
||||
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
|
||||
<ItemGroup>
|
||||
<FilteredAnalyzer Include="@(Analyzer->Distinct())" />
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
<Analyzer Include="@(FilteredAnalyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
+1
-5
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Daybreak.Exceptions;
|
||||
namespace Daybreak.Shared.Exceptions;
|
||||
|
||||
public sealed class CredentialsNotFoundException : Exception
|
||||
{
|
||||
@@ -13,9 +12,6 @@ public sealed class CredentialsNotFoundException : Exception
|
||||
{
|
||||
}
|
||||
|
||||
public CredentialsNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public CredentialsNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
+1
-5
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Daybreak.Exceptions;
|
||||
namespace Daybreak.Shared.Exceptions;
|
||||
|
||||
public sealed class ExecutableNotFoundException : Exception
|
||||
{
|
||||
@@ -13,9 +12,6 @@ public sealed class ExecutableNotFoundException : Exception
|
||||
{
|
||||
}
|
||||
|
||||
public ExecutableNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ExecutableNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
+1
-6
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Daybreak.Exceptions;
|
||||
namespace Daybreak.Shared.Exceptions;
|
||||
|
||||
public sealed class FatalException : Exception
|
||||
{
|
||||
@@ -13,10 +12,6 @@ public sealed class FatalException : Exception
|
||||
{
|
||||
}
|
||||
|
||||
public FatalException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public FatalException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Daybreak")]
|
||||
|
||||
namespace Daybreak.Shared;
|
||||
|
||||
public static class Global
|
||||
{
|
||||
//Will get set by Daybreak on application startup
|
||||
public static IServiceProvider GlobalServiceProvider { get; internal set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public readonly struct ApplicationLauncherContext
|
||||
{
|
||||
public string ExecutablePath { get; init; }
|
||||
public Process Process { get; init; }
|
||||
public uint ProcessId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class BackgroundResponse
|
||||
{
|
||||
public ImageSource? ImageSource { get; set; }
|
||||
public string? CreditText { get; set; }
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Daybreak.Models;
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public class BatchedObservableCollection<T> : ObservableCollection<T>
|
||||
{
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
public sealed class BrowserHistory
|
||||
{
|
||||
public List<string> History { get; set; } = [];
|
||||
public int CurrentPosition { get; set; } = -1;
|
||||
}
|
||||
+4
-2
@@ -1,7 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace Daybreak.Models.Browser;
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
|
||||
public class BrowserPayload
|
||||
{
|
||||
@@ -9,7 +9,9 @@ public class BrowserPayload
|
||||
public enum PayloadKeys
|
||||
{
|
||||
None,
|
||||
ContextMenu
|
||||
ContextMenu,
|
||||
XButton1Pressed,
|
||||
XButton2Pressed
|
||||
}
|
||||
|
||||
[JsonProperty(nameof(Key))]
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.Browser;
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
|
||||
public sealed class DownloadPayload
|
||||
{
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Models.Browser;
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
|
||||
public sealed class OnContextMenuPayload
|
||||
{
|
||||
@@ -10,4 +10,6 @@ public sealed class OnContextMenuPayload
|
||||
public double Y { get; set; }
|
||||
[JsonProperty(nameof(Selection))]
|
||||
public string? Selection { get; set; }
|
||||
[JsonProperty(nameof(Url))]
|
||||
public string? Url { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class BuildWithTemplateCode
|
||||
{
|
||||
public IBuildEntry? Build { get; set; }
|
||||
public string? TemplateCode { get; set; }
|
||||
}
|
||||
+5
-4
@@ -1,13 +1,15 @@
|
||||
using System.ComponentModel;
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Attribute = Daybreak.Shared.Models.Guildwars.Attribute;
|
||||
|
||||
namespace Daybreak.Models.Builds;
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
|
||||
public sealed class AttributeEntry : INotifyPropertyChanged
|
||||
{
|
||||
private Attribute? attribute;
|
||||
private int points;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public Attribute? Attribute
|
||||
{
|
||||
get => this.attribute;
|
||||
@@ -26,6 +28,5 @@ public sealed class AttributeEntry : INotifyPropertyChanged
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Points)));
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
public override string ToString() => $"{this.Attribute?.Name} - {this.Points}";
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
public interface IBuildEntry
|
||||
{
|
||||
public DateTimeOffset CreationTime { get; set; }
|
||||
public Dictionary<string, string>? Metadata { get; set; }
|
||||
public string? SourceUrl { get; set; }
|
||||
public string? PreviousName { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
+130
-63
@@ -1,135 +1,182 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Attribute = Daybreak.Shared.Models.Guildwars.Attribute;
|
||||
|
||||
namespace Daybreak.Models.Builds;
|
||||
|
||||
public sealed class BuildEntry : INotifyPropertyChanged
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
public sealed class SingleBuildEntry : BuildEntryBase, IBuildEntry, INotifyPropertyChanged, IEquatable<SingleBuildEntry>
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
private string? name;
|
||||
private Build? build;
|
||||
|
||||
public string? PreviousName { get; set; }
|
||||
public string? Name
|
||||
{
|
||||
get => this.name;
|
||||
set
|
||||
{
|
||||
this.name = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Name)));
|
||||
}
|
||||
}
|
||||
public Build? Build
|
||||
{
|
||||
get => this.build;
|
||||
set
|
||||
{
|
||||
this.build = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Build)));
|
||||
}
|
||||
}
|
||||
public Profession Primary
|
||||
{
|
||||
get => this.Build!.Primary;
|
||||
get;
|
||||
set
|
||||
{
|
||||
this.Build!.Primary = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Primary)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.UpdateAttributes();
|
||||
this.OnPropertyChanged(nameof(this.Primary));
|
||||
}
|
||||
}
|
||||
} = Profession.None;
|
||||
public Profession Secondary
|
||||
{
|
||||
get => this.Build!.Secondary;
|
||||
get;
|
||||
set
|
||||
{
|
||||
this.Build!.Secondary = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Secondary)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.UpdateAttributes();
|
||||
this.OnPropertyChanged(nameof(this.Secondary));
|
||||
}
|
||||
}
|
||||
} = Profession.None;
|
||||
public List<AttributeEntry> Attributes
|
||||
{
|
||||
get => this.Build!.Attributes;
|
||||
get;
|
||||
set
|
||||
{
|
||||
this.Build!.Attributes = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Attributes)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.UpdateSkills();
|
||||
this.OnPropertyChanged(nameof(this.Attributes));
|
||||
}
|
||||
}
|
||||
} = [];
|
||||
public List<Skill> Skills
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.OnPropertyChanged(nameof(this.Skills));
|
||||
}
|
||||
} = [Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill];
|
||||
public Skill FirstSkill
|
||||
{
|
||||
get => this.Build!.Skills[0];
|
||||
get => this.Skills[0];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[0] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.FirstSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[0] = value;
|
||||
this.OnPropertyChanged(nameof(this.FirstSkill));
|
||||
}
|
||||
}
|
||||
public Skill SecondSkill
|
||||
{
|
||||
get => this.Build!.Skills[1];
|
||||
get => this.Skills[1];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[1] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.SecondSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[1] = value;
|
||||
this.OnPropertyChanged(nameof(this.SecondSkill));
|
||||
}
|
||||
}
|
||||
public Skill ThirdSkill
|
||||
{
|
||||
get => this.Build!.Skills[2];
|
||||
get => this.Skills[2];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[2] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.ThirdSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[2] = value;
|
||||
this.OnPropertyChanged(nameof(this.ThirdSkill));
|
||||
}
|
||||
}
|
||||
public Skill FourthSkill
|
||||
{
|
||||
get => this.Build!.Skills[3];
|
||||
get => this.Skills[3];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[3] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.FourthSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[3] = value;
|
||||
this.OnPropertyChanged(nameof(this.FourthSkill));
|
||||
}
|
||||
}
|
||||
public Skill FifthSkill
|
||||
{
|
||||
get => this.Build!.Skills[4];
|
||||
get => this.Skills[4];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[4] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.FifthSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[4] = value;
|
||||
this.OnPropertyChanged(nameof(this.FifthSkill));
|
||||
}
|
||||
}
|
||||
public Skill SixthSkill
|
||||
{
|
||||
get => this.Build!.Skills[5];
|
||||
get => this.Skills[5];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[5] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.SixthSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[5] = value;
|
||||
this.OnPropertyChanged(nameof(this.SixthSkill));
|
||||
}
|
||||
}
|
||||
public Skill SeventhSkill
|
||||
{
|
||||
get => this.Build!.Skills[6];
|
||||
get => this.Skills[6];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[6] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.SeventhSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[6] = value;
|
||||
this.OnPropertyChanged(nameof(this.SeventhSkill));
|
||||
}
|
||||
}
|
||||
public Skill EigthSkill
|
||||
{
|
||||
get => this.Build!.Skills[7];
|
||||
get => this.Skills[7];
|
||||
set
|
||||
{
|
||||
this.Build!.Skills[7] = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.EigthSkill)));
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[7] = value;
|
||||
this.OnPropertyChanged(nameof(this.EigthSkill));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,4 +259,24 @@ public sealed class BuildEntry : INotifyPropertyChanged
|
||||
this.EigthSkill = Skill.NoSkill;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(SingleBuildEntry? other)
|
||||
{
|
||||
return this.Name == other?.Name &&
|
||||
this.PreviousName == other?.PreviousName &&
|
||||
this.SourceUrl == other?.SourceUrl &&
|
||||
this.Primary == other?.Primary &&
|
||||
this.Secondary == other?.Secondary &&
|
||||
this.Skills.SequenceEqual(other.Skills);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return this.Equals(obj as SingleBuildEntry);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(this.Name, this.PreviousName, this.SourceUrl, this.Primary.Name, this.Secondary.Name, string.Join(';', this.Skills.Select(s => s.Id)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
public sealed class TeamBuildEntry : BuildEntryBase, IEquatable<TeamBuildEntry>
|
||||
{
|
||||
public List<SingleBuildEntry> Builds
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
field = value;
|
||||
this.OnPropertyChanged(nameof(this.Builds));
|
||||
}
|
||||
} = [];
|
||||
|
||||
public bool Equals(TeamBuildEntry? other)
|
||||
{
|
||||
return this.Name == other?.Name &&
|
||||
this.PreviousName == other?.PreviousName &&
|
||||
this.SourceUrl == other?.SourceUrl &&
|
||||
this.Builds.Select((thisBuild, index) =>
|
||||
{
|
||||
var otherBuild = other?.Builds.Skip(index).FirstOrDefault();
|
||||
return thisBuild.Primary == otherBuild?.Primary &&
|
||||
thisBuild.Secondary == otherBuild?.Secondary &&
|
||||
thisBuild.Skills.SequenceEqual(otherBuild.Skills);
|
||||
}).All(result => result);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return this.Equals(obj as TeamBuildEntry);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(this.Name, this.PreviousName, this.SourceUrl, this.Builds.Select(c => c.GetHashCode()));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Models;
|
||||
namespace Daybreak.Shared.Models;
|
||||
public static class ColorPalette
|
||||
{
|
||||
public readonly static Color Red = Color.FromArgb(255, 213, 0, 0);
|
||||
@@ -24,8 +24,8 @@ public static class ColorPalette
|
||||
public readonly static Color BlueGrey = Color.FromArgb(255, 96, 125, 139);
|
||||
public readonly static Color Grey = Color.FromArgb(255, 158, 158, 158);
|
||||
|
||||
public readonly static List<Color> Colors = new()
|
||||
{
|
||||
public readonly static List<Color> Colors =
|
||||
[
|
||||
Pink,
|
||||
Amber,
|
||||
Purple,
|
||||
@@ -45,5 +45,5 @@ public static class ColorPalette
|
||||
Gold,
|
||||
BlueGrey,
|
||||
Grey
|
||||
};
|
||||
];
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models;
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public enum ColorScheme
|
||||
{
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Models;
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class ColoredTextElement
|
||||
{
|
||||
@@ -0,0 +1,8 @@
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class DownloadedBuild
|
||||
{
|
||||
public string? PreferredName { get; set; }
|
||||
public IBuildEntry? Build { get; set; }
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Models;
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class ElevationRequest
|
||||
{
|
||||
@@ -0,0 +1,16 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
namespace Daybreak.Models;
|
||||
public partial class EventViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
[GenerateNotifyPropertyChanged]
|
||||
private Event? seasonalEvent;
|
||||
[GenerateNotifyPropertyChanged]
|
||||
private bool active;
|
||||
[GenerateNotifyPropertyChanged]
|
||||
private bool upcoming;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class ExecutablePath : INotifyPropertyChanged
|
||||
{
|
||||
private string path = string.Empty;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public string Path
|
||||
{
|
||||
get => this.path;
|
||||
set
|
||||
{
|
||||
this.path = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models;
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public enum ExecutionPolicies
|
||||
{
|
||||
@@ -0,0 +1,12 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Daybreak.Shared.Models.LaunchConfigurations;
|
||||
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
/// <summary>
|
||||
/// XD Name
|
||||
/// </summary>
|
||||
internal sealed class PlayerContextMenuContext
|
||||
{
|
||||
public GuildWarsApplicationLaunchContext? GuildWarsApplicationLaunchContext { get; set; }
|
||||
public PlayerInformation? Player { get; set; }
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
namespace Daybreak.Models.FocusView;
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
|
||||
public sealed class QuestEntry : QuestLogEntry
|
||||
{
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
namespace Daybreak.Models.FocusView;
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
public sealed class QuestLocationEntry : QuestLogEntry
|
||||
{
|
||||
public override string Title { get; init; } = string.Empty;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.FocusView;
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
|
||||
public abstract class QuestLogEntry
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.FocusView;
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
public sealed class QuestLogSeparator : QuestLogEntry
|
||||
{
|
||||
public override string Title { get; init; } = string.Empty;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Models.Github;
|
||||
namespace Daybreak.Shared.Models.Github;
|
||||
|
||||
public sealed class GithubRefTag
|
||||
{
|
||||
@@ -0,0 +1,10 @@
|
||||
using Daybreak.Shared.Models.Progress;
|
||||
using System.Threading;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class GuildWarsUpdateRequest
|
||||
{
|
||||
public string? ExecutablePath { get; init; }
|
||||
public GuildwarsInstallationStatus? Status { get; init; }
|
||||
public CancellationToken CancellationToken { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class GuildWarsUpdateResponse
|
||||
{
|
||||
public bool Result { get; init; }
|
||||
public string? ExecutablePath { get; init; }
|
||||
}
|
||||
+49
-45
@@ -1,54 +1,57 @@
|
||||
using System;
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(AttributeJsonConverter))]
|
||||
public sealed class Attribute
|
||||
{
|
||||
public static Attribute FastCasting { get; } = new() { Name = "Fast Casting", Id = 0, Profession = Profession.Mesmer };
|
||||
public static Attribute IllusionMagic { get; } = new() { Name = "Illusion Magic", Id = 1, Profession = Profession.Mesmer };
|
||||
public static Attribute DominationMagic { get; } = new() { Name = "Domination Magic", Id = 2, Profession = Profession.Mesmer };
|
||||
public static Attribute InspirationMagic { get; } = new() { Name = "Inspiration Magic", Id = 3, Profession = Profession.Mesmer };
|
||||
public static Attribute BloodMagic { get; } = new() { Name = "Blood Magic", Id = 4, Profession = Profession.Necromancer };
|
||||
public static Attribute DeathMagic { get; } = new() { Name = "Death Magic", Id = 5, Profession = Profession.Necromancer };
|
||||
public static Attribute SoulReaping { get; } = new() { Name = "Soul Reaping", Id = 6, Profession = Profession.Necromancer };
|
||||
public static Attribute Curses { get; } = new() { Name = "Curses", Id = 7, Profession = Profession.Necromancer };
|
||||
public static Attribute AirMagic { get; } = new() { Name = "Air Magic", Id = 8, Profession = Profession.Elementalist };
|
||||
public static Attribute EarthMagic { get; } = new() { Name = "Earth Magic", Id = 9, Profession = Profession.Elementalist };
|
||||
public static Attribute FireMagic { get; } = new() { Name = "Fire Magic", Id = 10, Profession = Profession.Elementalist };
|
||||
public static Attribute WaterMagic { get; } = new() { Name = "Water Magic", Id = 11, Profession = Profession.Elementalist };
|
||||
public static Attribute EnergyStorage { get; } = new() { Name = "Energy Storage", Id = 12, Profession = Profession.Elementalist };
|
||||
public static Attribute HealingPrayers { get; } = new() { Name = "Healing Prayers", Id = 13, Profession = Profession.Monk };
|
||||
public static Attribute SmitingPrayers { get; } = new() { Name = "Smiting Prayers", Id = 14, Profession = Profession.Monk };
|
||||
public static Attribute ProtectionPrayers { get; } = new() { Name = "Protection Prayers", Id = 15, Profession = Profession.Monk };
|
||||
public static Attribute DivineFavor { get; } = new() { Name = "Divine Favor", Id = 16, Profession = Profession.Monk };
|
||||
public static Attribute Strength { get; } = new() { Name = "Strength", Id = 17, Profession = Profession.Warrior };
|
||||
public static Attribute AxeMastery { get; } = new() { Name = "Axe Mastery", Id = 18, Profession = Profession.Warrior };
|
||||
public static Attribute HammerMastery { get; } = new() { Name = "Hammer Mastery", Id = 19, Profession = Profession.Warrior };
|
||||
public static Attribute Swordsmanship { get; } = new() { Name = "Swordsmanship", Id = 20, Profession = Profession.Warrior };
|
||||
public static Attribute Tactics { get; } = new() { Name = "Tactics", Id = 21, Profession = Profession.Warrior };
|
||||
public static Attribute BeastMastery { get; } = new() { Name = "Beast Mastery", Id = 22, Profession = Profession.Ranger };
|
||||
public static Attribute Expertise { get; } = new() { Name = "Expertise", Id = 23, Profession = Profession.Ranger };
|
||||
public static Attribute WildernessSurvival { get; } = new() { Name = "Wilderness Survival", Id = 24, Profession = Profession.Ranger };
|
||||
public static Attribute Marksmanship { get; } = new() { Name = "Marksmanship", Id = 25, Profession = Profession.Ranger };
|
||||
public static Attribute DaggerMastery { get; } = new() { Name = "Dagger Mastery", Id = 29, Profession = Profession.Assassin };
|
||||
public static Attribute DeadlyArts { get; } = new() { Name = "Deadly Arts", Id = 30, Profession = Profession.Assassin };
|
||||
public static Attribute ShadowArts { get; } = new() { Name = "Shadow Arts", Id = 31, Profession = Profession.Assassin };
|
||||
public static Attribute Communing { get; } = new() { Name = "Communing", Id = 32, Profession = Profession.Ritualist };
|
||||
public static Attribute RestorationMagic { get; } = new() { Name = "Restoration Magic", Id = 33, Profession = Profession.Ritualist };
|
||||
public static Attribute ChannelingMagic { get; } = new() { Name = "Channeling Magic", Id = 34, Profession = Profession.Ritualist };
|
||||
public static Attribute CriticalStrikes { get; } = new() { Name = "Critical Strikes", Id = 35, Profession = Profession.Assassin };
|
||||
public static Attribute SpawningPower { get; } = new() { Name = "Spawning Power", Id = 36, Profession = Profession.Ritualist };
|
||||
public static Attribute SpearMastery { get; } = new() { Name = "Spear Mastery", Id = 37, Profession = Profession.Paragon };
|
||||
public static Attribute Command { get; } = new() { Name = "Command", Id = 38, Profession = Profession.Paragon };
|
||||
public static Attribute Motivation { get; } = new() { Name = "Motivation", Id = 39, Profession = Profession.Paragon };
|
||||
public static Attribute Leadership { get; } = new() { Name = "Leadership", Id = 40, Profession = Profession.Paragon };
|
||||
public static Attribute ScytheMastery { get; } = new() { Name = "Scythe Mastery", Id = 41, Profession = Profession.Dervish };
|
||||
public static Attribute WindPrayers { get; } = new() { Name = "Wind Prayers", Id = 42, Profession = Profession.Dervish };
|
||||
public static Attribute EarthPrayers { get; } = new() { Name = "Earth Prayers", Id = 43, Profession = Profession.Dervish };
|
||||
public static Attribute Mysticism { get; } = new() { Name = "Mysticism", Id = 44, Profession = Profession.Dervish };
|
||||
public static IEnumerable<Attribute> Attributes { get; } = new List<Attribute>
|
||||
public static readonly Attribute FastCasting = new() { Name = "Fast Casting", Id = 0, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute IllusionMagic = new() { Name = "Illusion Magic", Id = 1, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute DominationMagic = new() { Name = "Domination Magic", Id = 2, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute InspirationMagic = new() { Name = "Inspiration Magic", Id = 3, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute BloodMagic = new() { Name = "Blood Magic", Id = 4, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute DeathMagic = new() { Name = "Death Magic", Id = 5, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute SoulReaping = new() { Name = "Soul Reaping", Id = 6, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute Curses = new() { Name = "Curses", Id = 7, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute AirMagic = new() { Name = "Air Magic", Id = 8, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute EarthMagic = new() { Name = "Earth Magic", Id = 9, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute FireMagic = new() { Name = "Fire Magic", Id = 10, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute WaterMagic = new() { Name = "Water Magic", Id = 11, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute EnergyStorage = new() { Name = "Energy Storage", Id = 12, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute HealingPrayers = new() { Name = "Healing Prayers", Id = 13, Profession = Profession.Monk };
|
||||
public static readonly Attribute SmitingPrayers = new() { Name = "Smiting Prayers", Id = 14, Profession = Profession.Monk };
|
||||
public static readonly Attribute ProtectionPrayers = new() { Name = "Protection Prayers", Id = 15, Profession = Profession.Monk };
|
||||
public static readonly Attribute DivineFavor = new() { Name = "Divine Favor", Id = 16, Profession = Profession.Monk };
|
||||
public static readonly Attribute Strength = new() { Name = "Strength", Id = 17, Profession = Profession.Warrior };
|
||||
public static readonly Attribute AxeMastery = new() { Name = "Axe Mastery", Id = 18, Profession = Profession.Warrior };
|
||||
public static readonly Attribute HammerMastery = new() { Name = "Hammer Mastery", Id = 19, Profession = Profession.Warrior };
|
||||
public static readonly Attribute Swordsmanship = new() { Name = "Swordsmanship", Id = 20, Profession = Profession.Warrior };
|
||||
public static readonly Attribute Tactics = new() { Name = "Tactics", Id = 21, Profession = Profession.Warrior };
|
||||
public static readonly Attribute BeastMastery = new() { Name = "Beast Mastery", Id = 22, Profession = Profession.Ranger };
|
||||
public static readonly Attribute Expertise = new() { Name = "Expertise", Id = 23, Profession = Profession.Ranger };
|
||||
public static readonly Attribute WildernessSurvival = new() { Name = "Wilderness Survival", Id = 24, Profession = Profession.Ranger };
|
||||
public static readonly Attribute Marksmanship = new() { Name = "Marksmanship", Id = 25, Profession = Profession.Ranger };
|
||||
public static readonly Attribute DaggerMastery = new() { Name = "Dagger Mastery", Id = 29, Profession = Profession.Assassin };
|
||||
public static readonly Attribute DeadlyArts = new() { Name = "Deadly Arts", Id = 30, Profession = Profession.Assassin };
|
||||
public static readonly Attribute ShadowArts = new() { Name = "Shadow Arts", Id = 31, Profession = Profession.Assassin };
|
||||
public static readonly Attribute Communing = new() { Name = "Communing", Id = 32, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute RestorationMagic = new() { Name = "Restoration Magic", Id = 33, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute ChannelingMagic = new() { Name = "Channeling Magic", Id = 34, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute CriticalStrikes = new() { Name = "Critical Strikes", Id = 35, Profession = Profession.Assassin };
|
||||
public static readonly Attribute SpawningPower = new() { Name = "Spawning Power", Id = 36, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute SpearMastery = new() { Name = "Spear Mastery", Id = 37, Profession = Profession.Paragon };
|
||||
public static readonly Attribute Command = new() { Name = "Command", Id = 38, Profession = Profession.Paragon };
|
||||
public static readonly Attribute Motivation = new() { Name = "Motivation", Id = 39, Profession = Profession.Paragon };
|
||||
public static readonly Attribute Leadership = new() { Name = "Leadership", Id = 40, Profession = Profession.Paragon };
|
||||
public static readonly Attribute ScytheMastery = new() { Name = "Scythe Mastery", Id = 41, Profession = Profession.Dervish };
|
||||
public static readonly Attribute WindPrayers = new() { Name = "Wind Prayers", Id = 42, Profession = Profession.Dervish };
|
||||
public static readonly Attribute EarthPrayers = new() { Name = "Earth Prayers", Id = 43, Profession = Profession.Dervish };
|
||||
public static readonly Attribute Mysticism = new() { Name = "Mysticism", Id = 44, Profession = Profession.Dervish };
|
||||
public static readonly IEnumerable<Attribute> Attributes = new List<Attribute>
|
||||
{
|
||||
FastCasting,
|
||||
IllusionMagic,
|
||||
@@ -137,6 +140,7 @@ public sealed class Attribute
|
||||
public int Id { get; private set; }
|
||||
public string? Name { get; private set; }
|
||||
public Profession? Profession { get; private set; }
|
||||
public override string ToString() => this.Name ?? string.Empty;
|
||||
private Attribute()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class Build
|
||||
{
|
||||
public BuildMetadata? BuildMetadata { get; set; }
|
||||
public Profession Primary { get; set; } = Profession.None;
|
||||
public Profession Secondary { get; set; } = Profession.None;
|
||||
public List<AttributeEntry> Attributes { get; set; } = [];
|
||||
public List<Skill> Skills { get; set; } = [Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill];
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public abstract class BuildEntryBase : INotifyPropertyChanged, IBuildEntry
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public Dictionary<string, string>? Metadata { get; set; }
|
||||
public string? PreviousName { get; set; }
|
||||
public int? ToolboxBuildId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.ToolboxBuildId), out var toolBoxBuildString) is true &&
|
||||
int.TryParse(toolBoxBuildString, out var toolboxBuild))
|
||||
{
|
||||
return toolboxBuild;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.ToolboxBuildId)] = value.HasValue ? value.Value.ToString() : string.Empty;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.ToolboxBuildId)));
|
||||
}
|
||||
}
|
||||
public bool IsToolboxBuild
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.IsToolboxBuild), out var toolBoxBuildString) is true &&
|
||||
bool.TryParse(toolBoxBuildString, out var toolboxBuild))
|
||||
{
|
||||
return toolboxBuild;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.IsToolboxBuild)] = value.ToString();
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.IsToolboxBuild)));
|
||||
}
|
||||
}
|
||||
public DateTimeOffset CreationTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.CreationTime), out var creationTimeString) is true &&
|
||||
int.TryParse(creationTimeString, out var creationTimeUnix))
|
||||
{
|
||||
return DateTimeOffset.FromUnixTimeSeconds(creationTimeUnix);
|
||||
}
|
||||
|
||||
return DateTimeOffset.MinValue;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.CreationTime)] = value.ToUniversalTime().ToUnixTimeSeconds().ToString();
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.CreationTime)));
|
||||
}
|
||||
}
|
||||
public string? Name
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
field = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Name)));
|
||||
}
|
||||
}
|
||||
public string? SourceUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.SourceUrl), out var sourceUrl) is true)
|
||||
{
|
||||
return sourceUrl;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.SourceUrl)] = value ?? string.Empty;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.SourceUrl)));
|
||||
}
|
||||
}
|
||||
public List<PartyCompositionMetadataEntry>? PartyComposition
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.PartyComposition), out var serializedPartyComposition) is true &&
|
||||
!string.IsNullOrWhiteSpace(serializedPartyComposition))
|
||||
{
|
||||
return JsonConvert.DeserializeObject<List<PartyCompositionMetadataEntry>>(serializedPartyComposition);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(PartyCompositionMetadataEntry)] = value is null
|
||||
? string.Empty
|
||||
: JsonConvert.SerializeObject(value, Formatting.None);
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.PartyComposition)));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class BuildMetadata
|
||||
{
|
||||
@@ -16,7 +16,7 @@ public sealed class BuildMetadata
|
||||
public int SkillsLength { get; set; }
|
||||
public bool TailPresent { get; set; }
|
||||
public bool NewTemplate { get; set; }
|
||||
public List<int> SkillIds { get; set; } = new();
|
||||
public List<int> AttributesIds { get; set; } = new();
|
||||
public List<int> AttributePoints { get; set; } = new();
|
||||
public List<int> SkillIds { get; set; } = [];
|
||||
public List<int> AttributesIds { get; set; } = [];
|
||||
public List<int> AttributePoints { get; set; } = [];
|
||||
}
|
||||
+5
-2
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(CampaignJsonConverter))]
|
||||
public sealed class Campaign
|
||||
{
|
||||
public static Campaign Core { get; } = new()
|
||||
+5
-2
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(ContinentJsonConverter))]
|
||||
public sealed class Continent
|
||||
{
|
||||
public static Continent Tyria { get; } = new Continent
|
||||
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
/// <summary>
|
||||
/// Seasonal holidays and in-game events, as retrieved from https://www.guildwars.com/en/events.
|
||||
/// All events begin and end at 12pm UTC-7
|
||||
/// </summary>
|
||||
public sealed class Event
|
||||
{
|
||||
public static readonly Event WintersdayJanuary = new()
|
||||
{
|
||||
Title = "Wintersday",
|
||||
Description = "See towns glimmering with festive décor, deliver presents to needy little urchins, defeat the scheming Grentches, and spread Wintersday cheer to your fellow Tyrians! The fun culminates with a grand finale that runs every three hours on January 1!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wintersday",
|
||||
From = new DateOnly(1, 1, 1),
|
||||
To = new DateOnly(1, 1, 2)
|
||||
};
|
||||
|
||||
public static readonly Event CanthanNewYear = new()
|
||||
{
|
||||
Title = "Canthan New Year",
|
||||
Description = "Join the people of Cantha as they prepare a heavenly feast to honor the Celestial Animal of the coming year! This annual week-long celebration features Canthan cuisine, festive fireworks, special prizes, and the famed Shing Jea Boardwalk!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Canthan_New_Year",
|
||||
From = new DateOnly(1, 1, 31),
|
||||
To = new DateOnly(1, 2, 7)
|
||||
};
|
||||
|
||||
public static readonly Event LuckyTreatsWeek = new()
|
||||
{
|
||||
Title = "Lucky Treats Week",
|
||||
Description = "Shamrock Ale and Four-Leaf Clovers will be dropping throughout Tyria! Go fast, adventurers, and gather all the green you can before this special week ends!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Lucky_Treats_Week",
|
||||
From = new DateOnly(1, 3, 14),
|
||||
To = new DateOnly(1, 3, 21)
|
||||
};
|
||||
|
||||
public static readonly Event SweetTreatsWeek = new()
|
||||
{
|
||||
Title = "Sweet Treats Week",
|
||||
Description = "Sweet Treats Week is upon us, which means it’s time to load up on springtime goodies. Chocolate Bunnies and Golden Eggs will be randomly mixed in with regular drops all across Tyria. Get hopping!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Sweet_Treats_Week",
|
||||
From = new DateOnly(1, 4, 10),
|
||||
To = new DateOnly(1, 4, 17)
|
||||
};
|
||||
|
||||
public static readonly Event AnniversaryCelebration = new()
|
||||
{
|
||||
Title = "Guild Wars Anniversary Celebration",
|
||||
Description = "Guild Wars is another year older and the party just won't stop! Strap on your party hats, unpack your fireworks, and get ready to celebrate!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Anniversary_Celebration",
|
||||
From = new DateOnly(1, 4, 22),
|
||||
To = new DateOnly(1, 5, 6)
|
||||
};
|
||||
|
||||
public static readonly Event DragonFestival = new()
|
||||
{
|
||||
Title = "Dragon Festival",
|
||||
Description = "The Dragon Festival is almost upon us and Cantha is ready to roll out the red carpet. Time to stock up on bottle rockets, gorge on red bean cakes, and collect enough victory tokens for your pick of festival hats.",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Dragon_Festival",
|
||||
From = new DateOnly(1, 6, 27),
|
||||
To = new DateOnly(1, 7, 4)
|
||||
};
|
||||
|
||||
public static readonly Event WintersdayInJuly = new()
|
||||
{
|
||||
Title = "Wintersday In July",
|
||||
Description = "Just can't wait ‘til Wintersday? Jump into a mini version of Tyria’s famed winter celebration! Stock up on seasonal treats or target your friends in the Snowball Arena during this week-long celebration.",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wintersday_in_July",
|
||||
From = new DateOnly(1, 7, 24),
|
||||
To = new DateOnly(1, 7, 31)
|
||||
};
|
||||
|
||||
public static readonly Event WayfarersReverie = new()
|
||||
{
|
||||
Title = "Wayfarer's Reverie",
|
||||
Description = "The spirit of adventure beckons to you! It’s time to seek out the festival coordinator on each continent and start a quest to prove your adventuring prowess. Collect enough evidence of your travels and receive a special gift!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wayfarer%27s_Reverie",
|
||||
From = new DateOnly(1, 8, 25),
|
||||
To = new DateOnly(1, 9, 1)
|
||||
};
|
||||
|
||||
public static readonly Event PirateWeek = new()
|
||||
{
|
||||
Title = "Pirate Week",
|
||||
Description = "Avast! This seafaring celebration will have NPCs in Lion’s Arch and Kamadan talking like salty sea dogs. Join in the fun or walk the plank. Yarr!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Pirate_Week",
|
||||
From = new DateOnly(1, 9, 13),
|
||||
To = new DateOnly(1, 9, 20)
|
||||
};
|
||||
|
||||
public static readonly Event BreastCancerAwarenessMonth = new()
|
||||
{
|
||||
Title = "Breast Cancer Awareness Month",
|
||||
Description = "Sadie Salvitas arrives in Lion’s Arch on October 1 and will be selling vials of pink dye throughout the month in support of Breast Cancer Awareness.",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Login_screen_announcements/Archive#Breast_Cancer_Awareness_Month",
|
||||
From = new DateOnly(1, 10, 1),
|
||||
To = new DateOnly(1, 11, 2)
|
||||
};
|
||||
|
||||
public static readonly Event Halloween = new()
|
||||
{
|
||||
Title = "Halloween",
|
||||
Description = "Get ready for two whole weeks of mischief and mayhem in Tyria, courtesy of Mad King Thorn and his Lunatic Court. The madness escalates to the final event on October 31, when the Mad King himself appears every three hours—join if you dare!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Halloween",
|
||||
From = new DateOnly(1, 10, 18),
|
||||
To = new DateOnly(1, 11, 2)
|
||||
};
|
||||
|
||||
public static readonly Event SpecialTreatsWeek = new()
|
||||
{
|
||||
Title = "Special Treats Week",
|
||||
Description = "It's time for special, seasonal delights such as Slices of Pumpkin Pie and Hard Apple Cider to begin to drop all over Tyria. Gather what you can, but don't stuff yourself; Wintersday is just around the corner!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Special_Treats_Week",
|
||||
From = new DateOnly(1, 11, 21),
|
||||
To = new DateOnly(1, 11, 28)
|
||||
};
|
||||
|
||||
public static readonly Event WintersdayDecember = new()
|
||||
{
|
||||
Title = "Wintersday",
|
||||
Description = "See towns glimmering with festive décor, deliver presents to needy little urchins, defeat the scheming Grentches, and spread Wintersday cheer to your fellow Tyrians! The fun culminates with a grand finale that runs every three hours on January 1!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wintersday",
|
||||
From = new DateOnly(1, 12, 19),
|
||||
To = new DateOnly(1, 12, 31)
|
||||
};
|
||||
|
||||
public static readonly Event AprilFoolsDay = new()
|
||||
{
|
||||
Title = "April Fools' Day",
|
||||
Description = "*CLASSIFIED INFORMATION*\r\nTGlzdGVuLC Bhbm Qgd W5kZXJz dG FuZC4g VG hhd CBBbm5 paG lsYXRv c iBnb 2xlbSBp cyBvdXQ gd Ghlcm UuIEl0 IGN hb id0IG JlIGJ h cmdh aW5lZ CB3 aX RoL iBJdCBj YW4n d CBiZ SByZWF zb25lZ C B3aX RoLi BJd C Bkb2 Vzbid0I GZlZWwgcGl 0eS wgb3 I gcmVtb3Jz ZSwg b3I gZmV hci4g QW5 kIGl 0IGFi c2 9s dXRl bHk gd2lsbC Bub 3Qgc 3RvcC wgZX Zlc iwg dW50aW w gU2Fy YWggY W5kIE d3Z W4 gYXJ lIGRl YWQu",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/April_Fools%27_Day",
|
||||
From = new DateOnly(1, 4, 1),
|
||||
To = new DateOnly(1, 4, 2)
|
||||
};
|
||||
|
||||
public static readonly IEnumerable<Event> Events =
|
||||
[
|
||||
WintersdayJanuary,
|
||||
CanthanNewYear,
|
||||
LuckyTreatsWeek,
|
||||
AprilFoolsDay,
|
||||
SweetTreatsWeek,
|
||||
AnniversaryCelebration,
|
||||
DragonFestival,
|
||||
WintersdayInJuly,
|
||||
WayfarersReverie,
|
||||
PirateWeek,
|
||||
BreastCancerAwarenessMonth,
|
||||
Halloween,
|
||||
SpecialTreatsWeek,
|
||||
WintersdayDecember
|
||||
];
|
||||
|
||||
public string? Title { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public string? WikiUrl { get; set; }
|
||||
|
||||
public DateOnly From { get; set; }
|
||||
|
||||
public DateOnly To { get; set; }
|
||||
|
||||
private Event()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
public sealed class Hero : IWikiEntity
|
||||
{
|
||||
public static readonly Hero None = new() { Id = 0, Profession = Profession.None };
|
||||
public static readonly Hero Norgu = new() { Id = 1, Name = "Norgu", WikiUrl = "https://wiki.guildwars.com/wiki/Norgu", Profession = Profession.Mesmer };
|
||||
public static readonly Hero Goren = new() { Id = 2, Name = "Goren", WikiUrl = "https://wiki.guildwars.com/wiki/Goren", Profession = Profession.Warrior };
|
||||
public static readonly Hero Tahlkora = new() { Id = 3, Name = "Tahlkora", WikiUrl = "https://wiki.guildwars.com/wiki/Tahlkora", Profession = Profession.Monk };
|
||||
public static readonly Hero MasterOfWhispers = new() { Id = 4, Name = "Master of Whispers", WikiUrl = "https://wiki.guildwars.com/wiki/Master_of_Whispers", Profession = Profession.Necromancer };
|
||||
public static readonly Hero AcolyteJin = new() { Id = 5, Name = "Acolyte Jin", WikiUrl = "https://wiki.guildwars.com/wiki/Acolyte_Jin", Profession = Profession.Ranger };
|
||||
public static readonly Hero Koss = new() { Id = 6, Name = "Koss", WikiUrl = "https://wiki.guildwars.com/wiki/Koss", Profession = Profession.Warrior };
|
||||
public static readonly Hero Dunkoro = new() { Id = 7, Name = "Dunkoro", WikiUrl = "https://wiki.guildwars.com/wiki/Dunkoro", Profession = Profession.Monk };
|
||||
public static readonly Hero AcolyteSousuke = new() { Id = 8, Name = "Acolyte Sousuke", WikiUrl = "https://wiki.guildwars.com/wiki/Acolyte_Sousuke", Profession = Profession.Elementalist };
|
||||
public static readonly Hero Melonni = new() { Id = 9, Name = "Melonni", WikiUrl = "https://wiki.guildwars.com/wiki/Melonni", Profession = Profession.Dervish };
|
||||
public static readonly Hero ZhedShadowhoof = new() { Id = 10, Name = "Zhed Shadowhoof", WikiUrl = "https://wiki.guildwars.com/wiki/Zhed_Shadowhoof", Profession = Profession.Elementalist };
|
||||
public static readonly Hero GeneralMorgahn = new() { Id = 11, Name = "General Morgahn", WikiUrl = "https://wiki.guildwars.com/wiki/General_Morgahn", Profession = Profession.Paragon };
|
||||
public static readonly Hero MagridTheSly = new() { Id = 12, Name = "Magrid the Sly", WikiUrl = "https://wiki.guildwars.com/wiki/Magrid_the_Sly", Profession = Profession.Ranger };
|
||||
public static readonly Hero Zenmai = new() { Id = 13, Name = "Zenmai", WikiUrl = "https://wiki.guildwars.com/wiki/Zenmai", Profession = Profession.Assassin };
|
||||
public static readonly Hero Olias = new() { Id = 14, Name = "Olias", WikiUrl = "https://wiki.guildwars.com/wiki/Olias", Profession = Profession.Necromancer };
|
||||
public static readonly Hero Razah = new() { Id = 15, Name = "Razah", WikiUrl = "https://wiki.guildwars.com/wiki/Razah", Profession = Profession.None };
|
||||
public static readonly Hero MOX = new() { Id = 16, Name = "M.O.X.", WikiUrl = "https://wiki.guildwars.com/wiki/M.O.X.", Profession = Profession.Dervish };
|
||||
public static readonly Hero KeiranThackeray = new() { Id = 17, Name = "Keiran Thackeray", WikiUrl = "https://wiki.guildwars.com/wiki/Keiran_Thackeray", Profession = Profession.Paragon };
|
||||
public static readonly Hero Jora = new() { Id = 18, Name = "Jora", WikiUrl = "https://wiki.guildwars.com/wiki/Jora", Profession = Profession.Warrior };
|
||||
public static readonly Hero PyreFierceshot = new() { Id = 19, Name = "Pyre Fierceshot", WikiUrl = "https://wiki.guildwars.com/wiki/Pyre_Fierceshot", Profession = Profession.Ranger };
|
||||
public static readonly Hero Anton = new() { Id = 20, Name = "Anton", WikiUrl = "https://wiki.guildwars.com/wiki/Anton", Profession = Profession.Assassin };
|
||||
public static readonly Hero Livia = new() { Id = 21, Name = "Livia", WikiUrl = "https://wiki.guildwars.com/wiki/Livia", Profession = Profession.Necromancer };
|
||||
public static readonly Hero Hayda = new() { Id = 22, Name = "Hayda", WikiUrl = "https://wiki.guildwars.com/wiki/Hayda", Profession = Profession.Paragon };
|
||||
public static readonly Hero Kahmu = new() { Id = 23, Name = "Kahmu", WikiUrl = "https://wiki.guildwars.com/wiki/Kahmu", Profession = Profession.Dervish };
|
||||
public static readonly Hero Gwen = new() { Id = 24, Name = "Gwen", WikiUrl = "https://wiki.guildwars.com/wiki/Gwen", Profession = Profession.Mesmer };
|
||||
public static readonly Hero Xandra = new() { Id = 25, Name = "Xandra", WikiUrl = "https://wiki.guildwars.com/wiki/Xandra", Profession = Profession.Ritualist };
|
||||
public static readonly Hero Vekk = new() { Id = 26, Name = "Vekk", WikiUrl = "https://wiki.guildwars.com/wiki/Vekk", Profession = Profession.Elementalist };
|
||||
public static readonly Hero OgdenStonehealer = new() { Id = 27, Name = "Ogden Stonehealer", WikiUrl = "https://wiki.guildwars.com/wiki/Ogden_Stonehealer", Profession = Profession.Monk };
|
||||
public static readonly Hero Merc1 = new() { Id = 28, Name = "Mercenary Hero 1", Profession = Profession.None };
|
||||
public static readonly Hero Merc2 = new() { Id = 29, Name = "Mercenary Hero 2", Profession = Profession.None };
|
||||
public static readonly Hero Merc3 = new() { Id = 30, Name = "Mercenary Hero 3", Profession = Profession.None };
|
||||
public static readonly Hero Merc4 = new() { Id = 31, Name = "Mercenary Hero 4", Profession = Profession.None };
|
||||
public static readonly Hero Merc5 = new() { Id = 32, Name = "Mercenary Hero 5", Profession = Profession.None };
|
||||
public static readonly Hero Merc6 = new() { Id = 33, Name = "Mercenary Hero 6", Profession = Profession.None };
|
||||
public static readonly Hero Merc7 = new() { Id = 34, Name = "Mercenary Hero 7", Profession = Profession.None };
|
||||
public static readonly Hero Merc8 = new() { Id = 35, Name = "Mercenary Hero 8", Profession = Profession.None };
|
||||
public static readonly Hero Miku = new() { Id = 36, Name = "Miku", WikiUrl = "https://wiki.guildwars.com/wiki/Miku", Profession = Profession.Assassin };
|
||||
public static readonly Hero ZeiRi = new() { Id = 37, Name = "Zei Ri", WikiUrl = "https://wiki.guildwars.com/wiki/Zei_Ri", Profession = Profession.Ritualist };
|
||||
|
||||
public static readonly List<Hero> Heroes = [
|
||||
None,
|
||||
Norgu,
|
||||
Goren,
|
||||
Tahlkora,
|
||||
MasterOfWhispers,
|
||||
AcolyteJin,
|
||||
Koss,
|
||||
Dunkoro,
|
||||
AcolyteSousuke,
|
||||
Melonni,
|
||||
ZhedShadowhoof,
|
||||
GeneralMorgahn,
|
||||
MagridTheSly,
|
||||
Zenmai,
|
||||
Olias,
|
||||
Razah,
|
||||
MOX,
|
||||
KeiranThackeray,
|
||||
Jora,
|
||||
PyreFierceshot,
|
||||
Anton,
|
||||
Livia,
|
||||
Hayda,
|
||||
Kahmu,
|
||||
Gwen,
|
||||
Xandra,
|
||||
Vekk,
|
||||
OgdenStonehealer,
|
||||
Merc1,
|
||||
Merc2,
|
||||
Merc3,
|
||||
Merc4,
|
||||
Merc5,
|
||||
Merc6,
|
||||
Merc7,
|
||||
Merc8,
|
||||
Miku,
|
||||
ZeiRi
|
||||
];
|
||||
|
||||
public static bool TryParse(int id, out Hero hero)
|
||||
{
|
||||
hero = Heroes.Where(n => n.Id == id).FirstOrDefault()!;
|
||||
if (hero is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool TryParse(string name, out Hero hero)
|
||||
{
|
||||
hero = Heroes.Where(n => n.Name == name).FirstOrDefault()!;
|
||||
if (hero is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static Hero Parse(int id)
|
||||
{
|
||||
if (TryParse(id, out var hero) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a hero with id {id}");
|
||||
}
|
||||
|
||||
return hero;
|
||||
}
|
||||
public static Hero Parse(string name)
|
||||
{
|
||||
if (TryParse(name, out var hero) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a hero with name {name}");
|
||||
}
|
||||
|
||||
return hero;
|
||||
}
|
||||
|
||||
private Hero()
|
||||
{
|
||||
}
|
||||
|
||||
public int Id { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? WikiUrl { get; init; }
|
||||
public required Profession Profession { get; init; }
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public interface IIconUrlEntity
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public interface IItemModHash
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public interface IWikiEntity
|
||||
{
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class Inscription : ItemBase, IWikiEntity, IIconUrlEntity
|
||||
{
|
||||
@@ -10,12 +10,12 @@ public sealed class Inscription : ItemBase, IWikiEntity, IIconUrlEntity
|
||||
|
||||
public static readonly Inscription FocusOrShieldInscription = new() { Id = 15541, Name = "Focus Items or Shields Inscription", WikiUrl = "https://wiki.guildwars.com/wiki/Inscription", IconUrl = "https://wiki.guildwars.com/images/6/61/Inscription_focus_items_or_shields.png" };
|
||||
|
||||
public static IReadOnlyList<Inscription> Inscriptions { get; } = new List<Inscription>
|
||||
{
|
||||
public static IReadOnlyList<Inscription> Inscriptions { get; } =
|
||||
[
|
||||
WeaponInscription,
|
||||
FocusInscription,
|
||||
FocusOrShieldInscription
|
||||
};
|
||||
];
|
||||
|
||||
public string? WikiUrl { get; init; }
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public enum InstanceType
|
||||
{
|
||||
+9
-4
@@ -1,8 +1,12 @@
|
||||
using System;
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(ItemBaseJsonConverter))]
|
||||
public abstract class ItemBase
|
||||
{
|
||||
public static IReadOnlyCollection<ItemBase> AllItems { get; } = Enumerable.Empty<ItemBase>()
|
||||
@@ -10,6 +14,7 @@ public abstract class ItemBase
|
||||
.Concat(Material.All)
|
||||
.Concat(Inscription.Inscriptions)
|
||||
.Concat(Rune.Runes)
|
||||
.Concat(VialOfDye.Vials)
|
||||
.ToList();
|
||||
|
||||
public static bool TryParse<T>(int id, IEnumerable<ItemModifier>? modifiers, out T item)
|
||||
@@ -82,7 +87,7 @@ public abstract class ItemBase
|
||||
i.Modifiers is not null)
|
||||
{
|
||||
return i.Modifiers.Count() == modifiers.Count() &&
|
||||
i.Modifiers.All(modifiers.Contains);
|
||||
i.Modifiers.All(i1 => modifiers.Any(i2 => i1.Modifier == i2.Modifier));
|
||||
}
|
||||
else if (i.Modifiers is not null)
|
||||
{
|
||||
@@ -125,7 +130,7 @@ public abstract class ItemBase
|
||||
throw new InvalidOperationException($"Could not find a item with name {name}");
|
||||
}
|
||||
|
||||
return item;
|
||||
return item!;
|
||||
}
|
||||
|
||||
private static ItemBase? FilterAndFirstOrDefault(Func<ItemBase, bool> filter) => AllItems
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
public readonly struct ItemModifier
|
||||
{
|
||||
public uint Modifier { get; init; }
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class LoginData
|
||||
{
|
||||
public string Email { get; init; } = string.Empty;
|
||||
public string PlayerName { get; init; } = string.Empty;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class MainPlayerData
|
||||
{
|
||||
+6
-5
@@ -1,25 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class MainPlayerInformation : IEntity
|
||||
public sealed class MainPlayerInformation
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public uint Timer { get; init; }
|
||||
public TitleInformation? TitleInformation { get; init; }
|
||||
public int Id { get; init; }
|
||||
public int Level { get; init; }
|
||||
public Position? Position { get; init; }
|
||||
public Position? Position { get; set; }
|
||||
public Profession? PrimaryProfession { get; init; }
|
||||
public Profession? SecondaryProfession { get; init; }
|
||||
public List<Profession>? UnlockedProfession { get; init; }
|
||||
public Build? CurrentBuild { get; init; }
|
||||
public float CurrentHealth { get; init; }
|
||||
public float CurrentHealth { get; set; }
|
||||
public float MaxHealth { get; init; }
|
||||
public float CurrentEnergy { get; init; }
|
||||
public float CurrentEnergy { get; set; }
|
||||
public float MaxEnergy { get; init; }
|
||||
public float HealthRegen { get; init; }
|
||||
public float EnergyRegen { get; init; }
|
||||
public float RotationAngle { get; set; }
|
||||
public bool HardModeUnlocked { get; init; }
|
||||
public uint Experience { get; init; }
|
||||
public uint Morale { get; init; }
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(MapJsonConverter))]
|
||||
public sealed class Map : IWikiEntity
|
||||
{
|
||||
public int Id { get; private set; }
|
||||
@@ -253,6 +256,7 @@ public sealed class Map : IWikiEntity
|
||||
public static readonly Map DwaynaVsGrenth = new() { Id = 253, Name = "Dwayna Vs Grenth", WikiUrl = "https://wiki.guildwars.com/wiki/Dwayna_Vs_Grenth" };
|
||||
public static readonly Map SunjiangDistrictExplorable = new() { Id = 254, Name = "Sunjiang District", WikiUrl = "https://wiki.guildwars.com/wiki/Sunjiang_District" };
|
||||
public static readonly Map NahpuiQuarterExplorable = new() { Id = 257, Name = "Nahpui Quarter", WikiUrl = "https://wiki.guildwars.com/wiki/Nahpui_Quarter" };
|
||||
public static readonly Map NahpuiQuarterExplorable2 = new() { Id = 265, Name = "Nahpui Quarter", WikiUrl = "https://wiki.guildwars.com/wiki/Nahpui_Quarter" };
|
||||
public static readonly Map UrgozsWarren = new() { Id = 266, Name = "Urgozs Warren", WikiUrl = "https://wiki.guildwars.com/wiki/Urgozs_Warren" };
|
||||
public static readonly Map TahnnakaiTempleExplorable = new() { Id = 267, Name = "Tahnnakai Temple", WikiUrl = "https://wiki.guildwars.com/wiki/Tahnnakai_Temple" };
|
||||
public static readonly Map AltrummRuins = new() { Id = 270, Name = "Altrumm Ruins", WikiUrl = "https://wiki.guildwars.com/wiki/Altrumm_Ruins" };
|
||||
@@ -352,6 +356,7 @@ public sealed class Map : IWikiEntity
|
||||
public static readonly Map YohlonHavenOutpost = new() { Id = 381, Name = "Yohlon Haven", WikiUrl = "https://wiki.guildwars.com/wiki/Yohlon_Haven" };
|
||||
public static readonly Map GandaraTheMoonFortress = new() { Id = 382, Name = "Gandara", WikiUrl = "https://wiki.guildwars.com/wiki/Gandara" };
|
||||
public static readonly Map TheFloodplainOfMahnkelon = new() { Id = 383, Name = "The Floodplain of Mahnkelon", WikiUrl = "https://wiki.guildwars.com/wiki/The_Floodplain_of_Mahnkelon" };
|
||||
public static readonly Map TheFloodplainOfMahnkelon2 = new() { Id = 384, Name = "The Floodplain of Mahnkelon", WikiUrl = "https://wiki.guildwars.com/wiki/The_Floodplain_of_Mahnkelon" };
|
||||
public static readonly Map LionsArchSunspearsinKryta = new() { Id = 385, Name = "Lion's Arch", WikiUrl = "https://wiki.guildwars.com/wiki/Lion's_Arch" };
|
||||
public static readonly Map TuraisProcession = new() { Id = 386, Name = "Turai's Procession", WikiUrl = "https://wiki.guildwars.com/wiki/Turai's_Procession" };
|
||||
public static readonly Map SunspearSanctuaryOutpost = new() { Id = 387, Name = "Sunspear Sanctuary", WikiUrl = "https://wiki.guildwars.com/wiki/Sunspear_Sanctuary" };
|
||||
@@ -378,6 +383,7 @@ public sealed class Map : IWikiEntity
|
||||
public static readonly Map TheKodashBazaarOutpost = new() { Id = 414, Name = "The Kodash Bazaar", WikiUrl = "https://wiki.guildwars.com/wiki/The_Kodash_Bazaar" };
|
||||
public static readonly Map LionsGate = new() { Id = 415, Name = "Lion's Gate", WikiUrl = "https://wiki.guildwars.com/wiki/Lion's_Gate" };
|
||||
public static readonly Map TheMirrorOfLyss = new() { Id = 416, Name = "The Mirror of Lyss", WikiUrl = "https://wiki.guildwars.com/wiki/The_Mirror_of_Lyss" };
|
||||
public static readonly Map TheMirrorOfLyss2 = new() { Id = 419, Name = "The Mirror of Lyss", WikiUrl = "https://wiki.guildwars.com/wiki/The_Mirror_of_Lyss" };
|
||||
public static readonly Map SecuretheRefuge = new() { Id = 420, Name = "Secure the Refuge", WikiUrl = "https://wiki.guildwars.com/wiki/Secure_the_Refuge" };
|
||||
public static readonly Map VentaCemetery = new() { Id = 421, Name = "Venta Cemetery", WikiUrl = "https://wiki.guildwars.com/wiki/Venta_Cemetery" };
|
||||
public static readonly Map KamadanJewelOfIstanExplorable = new() { Id = 422, Name = "Kamadan", WikiUrl = "https://wiki.guildwars.com/wiki/Kamadan" };
|
||||
@@ -491,6 +497,7 @@ public sealed class Map : IWikiEntity
|
||||
public static readonly Map DajkahInlet = new() { Id = 554, Name = "Dajkah Inlet", WikiUrl = "https://wiki.guildwars.com/wiki/Dajkah_Inlet" };
|
||||
public static readonly Map TheShadowNexus = new() { Id = 555, Name = "The Shadow Nexus", WikiUrl = "https://wiki.guildwars.com/wiki/The_Shadow_Nexus" };
|
||||
public static readonly Map SparkflySwamp = new() { Id = 556, Name = "Sparkfly Swamp", WikiUrl = "https://wiki.guildwars.com/wiki/Sparkfly_Swamp" };
|
||||
public static readonly Map SparkflySwamp2 = new() { Id = 558, Name = "Sparkfly Swamp", WikiUrl = "https://wiki.guildwars.com/wiki/Sparkfly_Swamp" };
|
||||
public static readonly Map GateOftheNightfallenLandsOutpost = new() { Id = 559, Name = "Gate of the Nightfallen Lands", WikiUrl = "https://wiki.guildwars.com/wiki/Gate_of_the_Nightfallen_Lands" };
|
||||
public static readonly Map CathedralofFlamesLevel1 = new() { Id = 560, Name = "Cathedral of Flames", WikiUrl = "https://wiki.guildwars.com/wiki/Cathedral_of_Flames" };
|
||||
public static readonly Map TheTroubledKeeper = new() { Id = 561, Name = "Gate of Torment", WikiUrl = "https://wiki.guildwars.com/wiki/Gate_of_Torment" };
|
||||
@@ -1053,6 +1060,7 @@ public sealed class Map : IWikiEntity
|
||||
YohlonHavenOutpost,
|
||||
GandaraTheMoonFortress,
|
||||
TheFloodplainOfMahnkelon,
|
||||
TheFloodplainOfMahnkelon2,
|
||||
LionsArchSunspearsinKryta,
|
||||
TuraisProcession,
|
||||
SunspearSanctuaryOutpost,
|
||||
@@ -1079,6 +1087,7 @@ public sealed class Map : IWikiEntity
|
||||
TheKodashBazaarOutpost,
|
||||
LionsGate,
|
||||
TheMirrorOfLyss,
|
||||
TheMirrorOfLyss2,
|
||||
SecuretheRefuge,
|
||||
VentaCemetery,
|
||||
KamadanJewelOfIstanExplorable,
|
||||
@@ -1192,6 +1201,7 @@ public sealed class Map : IWikiEntity
|
||||
DajkahInlet,
|
||||
TheShadowNexus,
|
||||
SparkflySwamp,
|
||||
SparkflySwamp2,
|
||||
GateOftheNightfallenLandsOutpost,
|
||||
CathedralofFlamesLevel1,
|
||||
TheTroubledKeeper,
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user