mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-19 14:55:24 +00:00
Compare commits
21
Commits
v0.9.8.151
...
v0.9.9.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17b3ed34db | ||
|
|
cce9cd34af | ||
|
|
6a80f8ee5d | ||
|
|
edb7f0d0bd | ||
|
|
8e69375338 | ||
|
|
d24ae98fb0 | ||
|
|
111b3ea632 | ||
|
|
cc1e759972 | ||
|
|
ad0527ed73 | ||
|
|
8ffbb918ea | ||
|
|
c27a0dba65 | ||
|
|
ad8305c66d | ||
|
|
29fe12f094 | ||
|
|
9dbe4c5eaf | ||
|
|
1e9aca3807 | ||
|
|
895da23f7d | ||
|
|
f788a10879 | ||
|
|
9fe4be0467 | ||
|
|
b1a7d3a111 | ||
|
|
8b9fdaaa30 | ||
|
|
60d5947535 |
@@ -50,7 +50,7 @@ jobs:
|
||||
LatestReleaseTag: ${{steps.getLatestTag.outputs.tag}}
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.x'
|
||||
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
echo "::set-env name=Version::$version"
|
||||
|
||||
- name: Create publish launcher files
|
||||
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=true -p:PublishTrimmed --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 }}
|
||||
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
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=true --self-contained true -o .\Publish
|
||||
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 }}
|
||||
|
||||
@@ -103,7 +103,13 @@ jobs:
|
||||
.\Scripts\BuildRelease.ps1 -version $env:Version
|
||||
shell: pwsh
|
||||
|
||||
- name: Publish release
|
||||
- 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.8
|
||||
with:
|
||||
mode: update
|
||||
@@ -113,6 +119,14 @@ jobs:
|
||||
github_token: ${{ env.GITHUB_TOKEN }}
|
||||
replace_assets: true
|
||||
body_mrkdwn: ${{ env.Changelog }}
|
||||
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 }}
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.x'
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
|
||||
# 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.
|
||||
@@ -70,7 +70,7 @@ 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: '8.x'
|
||||
|
||||
@@ -91,4 +91,4 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.x'
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpCompress" Version="0.34.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.35.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
<TargetFramework>net8.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,33 +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
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
else if (File.Exists(tempFile))
|
||||
{
|
||||
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("Deleting browser caches");
|
||||
@@ -46,16 +129,6 @@ catch(Exception)
|
||||
{
|
||||
}
|
||||
|
||||
Console.WriteLine("Deleting package");
|
||||
try
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Failed to delete {tempFile}.\n{e}");
|
||||
}
|
||||
|
||||
Console.WriteLine("Launching application");
|
||||
var process = new Process
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,7 +5,6 @@ using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NSubstitute;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Tests.Services;
|
||||
|
||||
@@ -54,8 +53,8 @@ public class BuildTemplateManagerTests
|
||||
{
|
||||
Primary = Profession.Assassin,
|
||||
Secondary = Profession.None,
|
||||
Attributes = new List<AttributeEntry>
|
||||
{
|
||||
Attributes =
|
||||
[
|
||||
new AttributeEntry
|
||||
{
|
||||
Attribute = Attribute.DaggerMastery,
|
||||
@@ -76,9 +75,9 @@ public class BuildTemplateManagerTests
|
||||
Attribute = Attribute.CriticalStrikes,
|
||||
Points = 11
|
||||
}
|
||||
},
|
||||
Skills = new List<Skill>
|
||||
{
|
||||
],
|
||||
Skills =
|
||||
[
|
||||
Skill.UnsuspectingStrike,
|
||||
Skill.WildStrike,
|
||||
Skill.CriticalStrike,
|
||||
@@ -87,7 +86,7 @@ public class BuildTemplateManagerTests
|
||||
Skill.CriticalEye,
|
||||
Skill.CriticalAgility,
|
||||
Skill.CriticalDefenses
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var encoded = this.buildTemplateManager.EncodeTemplate(build);
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{41AE
|
||||
Scripts\BuildRelease.ps1 = Scripts\BuildRelease.ps1
|
||||
Scripts\CompareVersions.ps1 = Scripts\CompareVersions.ps1
|
||||
Scripts\GetBuildVersion.ps1 = Scripts\GetBuildVersion.ps1
|
||||
Scripts\PushFilesToBlobStorage.ps1 = Scripts\PushFilesToBlobStorage.ps1
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0E30DDA0-2111-4E6C-851E-01DC34124FC2}"
|
||||
@@ -31,7 +32,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
.github\CODEOWNERS = .github\CODEOWNERS
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Daybreak.7ZipExtractor", "Daybreak.7ZipExtractor\Daybreak.7ZipExtractor.csproj", "{CA60F9AC-A496-4DB6-970E-ECE73B051C05}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak.7ZipExtractor", "Daybreak.7ZipExtractor\Daybreak.7ZipExtractor.csproj", "{CA60F9AC-A496-4DB6-970E-ECE73B051C05}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public sealed class OptionSynchronizationIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class OptionsSynchronizationIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Ascalon Trade Chat")]
|
||||
[OptionsIgnore]
|
||||
[OptionsSynchronizationIgnore]
|
||||
public sealed class AscalonTradeChatOptions : ITradeChatOptions
|
||||
{
|
||||
public string HttpsUri { get; set; } = "https://ascalon.gwtoolbox.com/";
|
||||
|
||||
@@ -4,7 +4,7 @@ using Newtonsoft.Json;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Background Provider")]
|
||||
public sealed class BackgroundProviderOptions
|
||||
internal sealed class BackgroundProviderOptions
|
||||
{
|
||||
[OptionName(Name = "Bloogum Client Enabled", Description = "When enabled, Background Provider will make use of Bloogum to get background images")]
|
||||
[JsonProperty(nameof(BloogumEnabled))]
|
||||
|
||||
@@ -3,9 +3,10 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Build Synchronization")]
|
||||
[OptionsName(Name = "Synchronization")]
|
||||
[OptionsIgnore]
|
||||
public sealed class BuildSynchronizationOptions
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class SynchronizationOptions
|
||||
{
|
||||
[JsonProperty(nameof(ProtectedGraphAccessToken))]
|
||||
public string? ProtectedGraphAccessToken { get; set; }
|
||||
|
||||
@@ -6,8 +6,9 @@ using System.Collections.Generic;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsIgnore]
|
||||
public sealed class CredentialManagerOptions
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class CredentialManagerOptions
|
||||
{
|
||||
[JsonProperty(nameof(ProtectedLoginCredentials))]
|
||||
public List<ProtectedLoginCredentials> ProtectedLoginCredentials { get; set; } = new();
|
||||
public List<ProtectedLoginCredentials> ProtectedLoginCredentials { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
[OptionsName(Name = "DSOAL")]
|
||||
public sealed class DSOALOptions
|
||||
internal sealed class DSOALOptions
|
||||
{
|
||||
[JsonProperty(nameof(Path))]
|
||||
[OptionName(Name = "Path", Description = "The path to the DSOAL installation")]
|
||||
[OptionSynchronizationIgnore]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
|
||||
@@ -4,10 +4,11 @@ using Newtonsoft.Json;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "DirectSong")]
|
||||
public sealed class DirectSongOptions
|
||||
internal sealed class DirectSongOptions
|
||||
{
|
||||
[JsonProperty(nameof(Path))]
|
||||
[OptionName(Name = "Path", Description = "Folder that contains the DirectSong files")]
|
||||
[OptionSynchronizationIgnore]
|
||||
public string Path { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Event Notifier")]
|
||||
public sealed class EventNotifierOptions
|
||||
internal sealed class EventNotifierOptions
|
||||
{
|
||||
[OptionName(Name = "Enabled", Description = "If set to true, Daybreak will notify the user of any event on startup")]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
@@ -4,8 +4,9 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
[OptionsIgnore]
|
||||
public sealed class GuildwarsExecutableOptions
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class GuildwarsExecutableOptions
|
||||
{
|
||||
[JsonProperty(nameof(ExecutablePaths))]
|
||||
public List<string> ExecutablePaths { get; set; } = new();
|
||||
public List<string> ExecutablePaths { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Memory Cache")]
|
||||
public sealed class ImageCacheOptions
|
||||
internal sealed class ImageCacheOptions
|
||||
{
|
||||
[OptionName(Name = "Image Cache Limit", Description = "The maximum number of MBs that will be used to cache images in memory")]
|
||||
[OptionRange<double>(MinValue = 0d, MaxValue = 1000d)]
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Kamadan Trade Chat")]
|
||||
[OptionsIgnore]
|
||||
[OptionsSynchronizationIgnore]
|
||||
public sealed class KamadanTradeChatOptions : ITradeChatOptions
|
||||
{
|
||||
public string HttpsUri { get; set; } = "https://kamadan.gwtoolbox.com/";
|
||||
|
||||
@@ -6,8 +6,9 @@ using System.Collections.Generic;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsIgnore]
|
||||
public sealed class LaunchConfigurationServiceOptions
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class LaunchConfigurationServiceOptions
|
||||
{
|
||||
[JsonProperty(nameof(LaunchConfigurations))]
|
||||
public List<LaunchConfiguration> LaunchConfigurations { get; set; } = new();
|
||||
public List<LaunchConfiguration> LaunchConfigurations { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Daybreak.Views;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
@@ -11,11 +10,13 @@ public sealed class LauncherOptions
|
||||
{
|
||||
[JsonProperty(nameof(SetGuildwarsWindowSizeOnLaunch))]
|
||||
[OptionName(Name = "Set GuildWars Window Size On Launch", Description = "Sets the GuildWars window size and position on launch")]
|
||||
[OptionSynchronizationIgnore]
|
||||
public bool SetGuildwarsWindowSizeOnLaunch { get; set; }
|
||||
|
||||
[JsonProperty(nameof(DesiredGuildwarsScreen))]
|
||||
[OptionName(Name = "Desired GuildWars Screen", Description = "Sets the screen on which the GuildWars window will be placed")]
|
||||
[OptionSetterView<ScreenChoiceView>(Action = "Screen Selector")]
|
||||
[OptionSynchronizationIgnore]
|
||||
public int DesiredGuildwarsScreen { get; set; }
|
||||
|
||||
[JsonProperty(nameof(LaunchGuildwarsAsCurrentUser))]
|
||||
@@ -24,6 +25,7 @@ public sealed class LauncherOptions
|
||||
|
||||
[JsonProperty(nameof(ShortcutLocation))]
|
||||
[OptionName(Name = "Shortcut Location", Description = "Location where the shortcut will be placed")]
|
||||
[OptionSynchronizationIgnore]
|
||||
public string? ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
|
||||
[JsonProperty(nameof(PlaceShortcut))]
|
||||
@@ -50,4 +52,8 @@ public sealed class LauncherOptions
|
||||
[JsonProperty(nameof(PersistentLogging))]
|
||||
[OptionName(Name = "Persistent Logging", Description = "If true, the launcher will save logs in the local database. Otherwise, the launcher will only keep logs in a memory cache")]
|
||||
public bool PersistentLogging { get; set; } = false;
|
||||
|
||||
[JsonProperty(nameof(BetaUpdate))]
|
||||
[OptionName(Name = "Beta Update", Description = "If true, the launcher will use the new update procedure")]
|
||||
public bool BetaUpdate { get; set; } = true;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Logging Options")]
|
||||
[OptionsIgnore]
|
||||
public sealed class LoggingOptions : ILiteCollectionOptions<Models.Log>
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class LoggingOptions : ILiteCollectionOptions<Models.Log>
|
||||
{
|
||||
public string CollectionName => "logs";
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Newtonsoft.Json;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Memory Reader")]
|
||||
public sealed class MemoryReaderOptions
|
||||
internal sealed class MemoryReaderOptions
|
||||
{
|
||||
[JsonProperty(nameof(MemoryReaderFrequency))]
|
||||
[OptionRange<double>(MinValue = 0, MaxValue = 1000)]
|
||||
|
||||
@@ -4,6 +4,7 @@ using Daybreak.Services.Notifications.Models;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsIgnore]
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class NotificationStorageOptions : ILiteCollectionOptions<NotificationDTO>
|
||||
{
|
||||
public string CollectionName => "notifications";
|
||||
|
||||
@@ -4,21 +4,13 @@ using Newtonsoft.Json;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Pathfinding")]
|
||||
public sealed class PathfindingOptions
|
||||
internal sealed class PathfindingOptions
|
||||
{
|
||||
[JsonProperty(nameof(EnablePathfinding))]
|
||||
[OptionName(Name = "Enable Pathfinding", Description = "If true, the pathfinder will attempt to produce paths from the player position to objectives")]
|
||||
public bool EnablePathfinding { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(ImprovedPathfinding))]
|
||||
[OptionName(Name = "Distance-Based Pathfinding", Description = "If true, the pathfinder will attempt use an improved algorithm to find paths. Slower but generally more precise")]
|
||||
public bool ImprovedPathfinding { get; set; } = false;
|
||||
|
||||
[JsonProperty(nameof(OptimizePaths))]
|
||||
[OptionName(Name = "Path Optimization", Description = "If true, the pathfinder will attempt to optimize paths. Slower but generally more precise")]
|
||||
public bool OptimizePaths { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(UseCaching))]
|
||||
[OptionName(Name = "Use Caching", Description = "If true, the pathfinder will use more memory to cache parts of the pathfinding algorithm")]
|
||||
public bool UseCaching { get; set; } = true;
|
||||
[JsonProperty(nameof(HighSensitivity))]
|
||||
[OptionName(Name = "High Sensitivity", Description = "If true, the pathfinder generate much more accurate paths. This will greatly increase memory usage and map load times")]
|
||||
public bool HighSensitivity { get; set; } = false;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ using System.Collections.Generic;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsIgnore]
|
||||
public sealed class PluginsServiceOptions
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class PluginsServiceOptions
|
||||
{
|
||||
public List<PluginEntry> EnabledPlugins { get; set; } = new();
|
||||
public List<PluginEntry> EnabledPlugins { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Price History")]
|
||||
[OptionsIgnore]
|
||||
public sealed class PriceHistoryOptions : ILiteCollectionOptions<TraderQuoteDTO>
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class PriceHistoryOptions : ILiteCollectionOptions<TraderQuoteDTO>
|
||||
{
|
||||
public string HttpsUri { get; set; } = "https://kamadan.gwtoolbox.com/";
|
||||
|
||||
@@ -15,5 +16,5 @@ public sealed class PriceHistoryOptions : ILiteCollectionOptions<TraderQuoteDTO>
|
||||
|
||||
public TimeSpan UpdateInterval { get; set; } = TimeSpan.FromHours(1);
|
||||
|
||||
public Dictionary<string, DateTime> ItemHistoryMetadata { get; set; } = new();
|
||||
public Dictionary<string, DateTime> ItemHistoryMetadata { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Newtonsoft.Json;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "ReShade")]
|
||||
public sealed class ReShadeOptions
|
||||
internal sealed class ReShadeOptions
|
||||
{
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, Daybreak will attempt to inject ReShade into the starting Guild Wars executable")]
|
||||
|
||||
@@ -4,7 +4,8 @@ namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Screen Manager")]
|
||||
[OptionsIgnore]
|
||||
public sealed class ScreenManagerOptions
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class ScreenManagerOptions
|
||||
{
|
||||
public double X { get; set; }
|
||||
public double Y { get; set; }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Sounds")]
|
||||
public sealed class SoundOptions
|
||||
internal sealed class SoundOptions
|
||||
{
|
||||
[OptionName(Name = "Sounds Enabled", Description = "If enabled, the client will play sounds.")]
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
@@ -21,6 +21,7 @@ public sealed class ThemeOptions
|
||||
[OptionName(Name = "Blur Background", Description = "If true, the background image will be blurred")]
|
||||
public bool BackgroundBlur { get; set; } = false;
|
||||
|
||||
[OptionIgnore]
|
||||
[OptionName(Name = "Wintersday Mode", Description = "If true, Daybreak will apply a Wintersday theme")]
|
||||
public bool WintersdayMode { get; set; } = false;
|
||||
public bool WintersdayMode => false;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@ using Newtonsoft.Json;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "GWToolbox")]
|
||||
public sealed class ToolboxOptions
|
||||
internal sealed class ToolboxOptions
|
||||
{
|
||||
[JsonProperty(nameof(DllPath))]
|
||||
[OptionName(Name = "DllPath", Description = "The path to GWToolboxdll.dll")]
|
||||
[OptionSynchronizationIgnore]
|
||||
public string? DllPath { get; set; }
|
||||
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
|
||||
@@ -5,10 +5,21 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsIgnore]
|
||||
public sealed class TradeAlertingOptions
|
||||
[OptionsName(Name = "Trade Alerts")]
|
||||
internal sealed class TradeAlertingOptions
|
||||
{
|
||||
[OptionIgnore]
|
||||
[OptionSynchronizationIgnore]
|
||||
public TimeSpan MaxLookbackPeriod { get; set; } = TimeSpan.FromDays(31);
|
||||
|
||||
[OptionIgnore]
|
||||
[OptionSynchronizationIgnore]
|
||||
public DateTime LastCheckTime { get; set; } = DateTime.MinValue;
|
||||
public List<TradeAlert> Alerts { get; set; } = new();
|
||||
|
||||
[OptionIgnore]
|
||||
public List<ITradeAlert> Alerts { get; set; } = [];
|
||||
|
||||
[OptionName(Name = "Quote Alerts Interval", Description = "The amount of seconds in between checking for alerts based on trade quotes")]
|
||||
[OptionRange<double>(MinValue = 30d, MaxValue = 1440d)]
|
||||
public double QuoteAlertsInterval { get; set; } = 30;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ using Daybreak.Services.TradeChat.Models;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsIgnore]
|
||||
public sealed class TraderMessagesOptions : ILiteCollectionOptions<TraderMessageDTO>
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class TraderMessagesOptions : ILiteCollectionOptions<TraderMessageDTO>
|
||||
{
|
||||
public string CollectionName => "trader_messages";
|
||||
}
|
||||
|
||||
@@ -4,15 +4,16 @@ using System;
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Trader Quotes")]
|
||||
public sealed class TraderQuotesOptions
|
||||
[OptionsSynchronizationIgnore]
|
||||
internal sealed class TraderQuotesOptions
|
||||
{
|
||||
[OptionIgnore]
|
||||
public string HttpsUri { get; set; } = "https://kamadan.gwtoolbox.com/";
|
||||
|
||||
[OptionIgnore]
|
||||
public DateTime LastCheckTime { get; set;} = DateTime.MinValue;
|
||||
[OptionName(Name = "Cache Update Interval", Description = "The amount of minutes in between cache updates")]
|
||||
|
||||
[OptionName(Name = "Cache Update Interval", Description = "The amount of minutes in between cache updates")]
|
||||
[OptionRange<double>(MinValue = 30d, MaxValue = 1440d)]
|
||||
public double CacheUpdateInterval { get; set; } = 60;
|
||||
}
|
||||
|
||||
@@ -18,5 +18,6 @@ public sealed class UModOptions
|
||||
|
||||
[JsonProperty(nameof(Mods))]
|
||||
[OptionIgnore]
|
||||
public List<UModEntry> Mods { get; set; } = new();
|
||||
[OptionSynchronizationIgnore]
|
||||
public List<UModEntry> Mods { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -218,6 +218,8 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
services.AddSingleton<IGWCAClient, GWCAClient>();
|
||||
services.AddSingleton<IGuildwarsMemoryReader, GWCAMemoryReader>();
|
||||
services.AddSingleton<ISevenZipExtractor, SevenZipExtractor>();
|
||||
services.AddSingleton<IGraphClient, GraphClient>();
|
||||
services.AddSingleton<IOptionsSynchronizationService, OptionsSynchronizationService>();
|
||||
services.AddScoped<ICredentialManager, CredentialManager>();
|
||||
services.AddScoped<IApplicationLauncher, ApplicationLauncher>();
|
||||
services.AddScoped<IScreenshotProvider, ScreenshotProvider>();
|
||||
@@ -227,14 +229,13 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
services.AddScoped<IIconCache, IconCache>();
|
||||
services.AddScoped<IPrivilegeManager, PrivilegeManager>();
|
||||
services.AddScoped<IScreenManager, ScreenManager>();
|
||||
services.AddScoped<IGraphClient, GraphClient>();
|
||||
services.AddScoped<IPathfinder, SharpNavPathfinder>();
|
||||
services.AddScoped<IOnboardingService, OnboardingService>();
|
||||
services.AddScoped<IExperienceCalculator, ExperienceCalculator>();
|
||||
services.AddScoped<IAttributePointCalculator, AttributePointCalculator>();
|
||||
services.AddScoped<IDownloadService, DownloadService>();
|
||||
services.AddScoped<IGuildwarsInstaller, GuildwarsInstaller>();
|
||||
services.AddScoped<IExceptionHandler, ExceptionHandler>();
|
||||
services.AddScoped<IPathfinder, StupidPathfinder>();
|
||||
services.AddScoped<IDrawingService, DrawingService>();
|
||||
services.AddScoped<IDrawingModuleProducer, DrawingService>(sp => sp.GetRequiredService<IDrawingService>().As<DrawingService>()!);
|
||||
services.AddScoped<ITradeChatService<KamadanTradeChatOptions>, TradeChatService<KamadanTradeChatOptions>>();
|
||||
@@ -294,6 +295,8 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
viewProducer.RegisterView<TradeAlertsView>();
|
||||
viewProducer.RegisterView<TradeAlertSetupView>();
|
||||
viewProducer.RegisterView<TradeNotificationView>();
|
||||
viewProducer.RegisterView<TradeAlertsChoiceView>();
|
||||
viewProducer.RegisterView<QuoteAlertSetupView>();
|
||||
viewProducer.RegisterView<GuildwarsCopySelectionView>();
|
||||
viewProducer.RegisterView<GuildwarsCopyView>();
|
||||
viewProducer.RegisterView<DSOALInstallingView>();
|
||||
@@ -317,6 +320,7 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
viewProducer.RegisterView<DirectSongInstallationChoiceView>();
|
||||
viewProducer.RegisterView<DirectSongOnboardingEntryView>();
|
||||
viewProducer.RegisterView<DirectSongSwitchView>();
|
||||
viewProducer.RegisterView<SettingsSynchronizationView>();
|
||||
}
|
||||
|
||||
public override void RegisterStartupActions(IStartupActionProducer startupActionProducer)
|
||||
@@ -390,7 +394,7 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
optionsProducer.RegisterOptions<ThemeOptions>();
|
||||
|
||||
optionsProducer.RegisterOptions<BrowserOptions>();
|
||||
optionsProducer.RegisterOptions<BuildSynchronizationOptions>();
|
||||
optionsProducer.RegisterOptions<SynchronizationOptions>();
|
||||
optionsProducer.RegisterOptions<FocusViewOptions>();
|
||||
|
||||
optionsProducer.RegisterOptions<MemoryReaderOptions>();
|
||||
|
||||
@@ -20,7 +20,7 @@ public partial class ExpandableMenuSection : UserControl
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool expanded = false;
|
||||
|
||||
public ObservableCollection<FrameworkElement> Children { get; } = new ObservableCollection<FrameworkElement>();
|
||||
public ObservableCollection<FrameworkElement> Children { get; } = [];
|
||||
|
||||
public ExpandableMenuSection()
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ public partial class GuildwarsMinimap : UserControl
|
||||
|
||||
private readonly Histogram<double> drawingLatency;
|
||||
private readonly DispatcherTimer dispatcherTimer = new(DispatcherPriority.Render);
|
||||
private readonly List<Position> mainPlayerPositionHistory = new();
|
||||
private readonly List<Position> mainPlayerPositionHistory = [];
|
||||
private readonly IPathfinder pathfinder;
|
||||
private readonly IDrawingService drawingService;
|
||||
private readonly IThemeManager themeManager;
|
||||
@@ -357,8 +357,8 @@ public partial class GuildwarsMinimap : UserControl
|
||||
this.drawingService.DrawEngagementArea(bitmap, this.GameData);
|
||||
this.drawingService.DrawMainPlayerPositionHistory(bitmap, this.mainPlayerPositionHistory);
|
||||
this.drawingService.DrawPaths(bitmap, this.pathfindingCache);
|
||||
this.drawingService.DrawQuestObjectives(bitmap, this.GameData.MainPlayer?.QuestLog ?? new List<QuestMetadata>());
|
||||
this.drawingService.DrawMapIcons(bitmap, this.GameData.MapIcons ?? new List<MapIcon>());
|
||||
this.drawingService.DrawQuestObjectives(bitmap, this.GameData.MainPlayer?.QuestLog ?? []);
|
||||
this.drawingService.DrawMapIcons(bitmap, this.GameData.MapIcons ?? []);
|
||||
this.drawingService.DrawEntities(bitmap, this.GameData, this.TargetEntityId);
|
||||
bitmap.Unlock();
|
||||
this.drawingLatency.Record(sw.ElapsedMilliseconds);
|
||||
|
||||
@@ -24,7 +24,7 @@ public partial class NotificationStackpanel : UserControl
|
||||
private readonly DispatcherTimer dispatcherTimer = new();
|
||||
private CancellationTokenSource? cancellationToken;
|
||||
|
||||
public ObservableCollection<NotificationWrapper> Notifications { get; } = new();
|
||||
public ObservableCollection<NotificationWrapper> Notifications { get; } = [];
|
||||
|
||||
public NotificationStackpanel() :
|
||||
this(Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<INotificationProducer>(),
|
||||
|
||||
@@ -15,7 +15,7 @@ public partial class EnumOptionTemplate : UserControl
|
||||
{
|
||||
private OptionProperty optionProperty = default!;
|
||||
|
||||
public ObservableCollection<object> PossibleEnumValues { get; } = new ObservableCollection<object>();
|
||||
public ObservableCollection<object> PossibleEnumValues { get; } = [];
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private object value = default!;
|
||||
|
||||
@@ -23,7 +23,7 @@ public partial class OptionsSection : UserControl
|
||||
private readonly IOptionsProvider optionsProvider;
|
||||
private readonly IViewManager viewManager;
|
||||
|
||||
public ObservableCollection<OptionSection> Options { get; } = new ObservableCollection<OptionSection>();
|
||||
public ObservableCollection<OptionSection> Options { get; } = [];
|
||||
|
||||
public OptionsSection(
|
||||
IOptionsProvider optionsProvider,
|
||||
|
||||
@@ -56,11 +56,11 @@ public partial class BuildTemplate : UserControl
|
||||
private int attributePoints;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private List<Skill> availableSkills = new();
|
||||
private List<Skill> availableSkills = [];
|
||||
|
||||
public event EventHandler? BuildChanged;
|
||||
public ObservableCollection<Profession> PrimaryProfessions { get; } = new();
|
||||
public ObservableCollection<Profession> SecondaryProfessions { get; } = new();
|
||||
public ObservableCollection<Profession> PrimaryProfessions { get; } = [];
|
||||
public ObservableCollection<Profession> SecondaryProfessions { get; } = [];
|
||||
|
||||
public BuildTemplate()
|
||||
: this(Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IBuildTemplateManager>(),
|
||||
|
||||
@@ -29,7 +29,7 @@ public partial class QuestLogTemplate : UserControl
|
||||
|
||||
public QuestLogTemplate()
|
||||
{
|
||||
this.quests = new List<QuestMetadata>();
|
||||
this.quests = [];
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public partial class TradeChatTemplate : UserControl
|
||||
[GenerateDependencyProperty]
|
||||
private TraderMessage selectedTraderMessage = default!;
|
||||
|
||||
public ObservableCollection<TraderMessageViewWrapper> TraderMessages { get; } = new();
|
||||
public ObservableCollection<TraderMessageViewWrapper> TraderMessages { get; } = [];
|
||||
|
||||
public TradeChatTemplate()
|
||||
: this(Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IWordHighlightingService>())
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.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.Models.Guildwars;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.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,78 @@
|
||||
using Daybreak.Models.Trade;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Daybreak.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.Services.TradeChat.Models;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.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;
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,15 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>Daybreak</RootNamespace>
|
||||
<!--Unable to migrate to .net 7 due to issues with font families not being found #140-->
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<Version>0.9.8.151</Version>
|
||||
<Version>0.9.9.2</Version>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
@@ -89,8 +87,9 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
||||
<PackageReference Include="DiffPlex" Version="1.7.2" />
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.55" />
|
||||
<PackageReference Include="ini-parser-netstandard" Version="2.5.2" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc2" />
|
||||
@@ -99,12 +98,13 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2151.40" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2210.55" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
|
||||
<PackageReference Include="NAudio" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Plumsy" Version="1.1.0" />
|
||||
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageReference Include="SharpNav" Version="0.9.2" />
|
||||
<PackageReference Include="Slim" Version="1.9.2" />
|
||||
<PackageReference Include="Svg" Version="3.4.6" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
|
||||
@@ -16,11 +16,16 @@ using Microsoft.Extensions.Logging;
|
||||
using Slim;
|
||||
using Slim.Integration.ServiceCollection;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media;
|
||||
|
||||
//The following lines are needed to expose internal objects to the test project
|
||||
[assembly: InternalsVisibleTo("Daybreak.Tests")]
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
|
||||
namespace Daybreak.Launch;
|
||||
|
||||
public sealed class Launcher : ExtendedApplication<MainWindow>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<BooleanToVisibilityConverter x:Key="BaseBooleanToVisibilityConverter" />
|
||||
<converters:BooleanToEffectConverter x:Key="BooleanToEffectConverter" />
|
||||
<effects:Kuwahara x:Key="PaintifyEffect" TexelWidth="200" TexelHeight="50" />
|
||||
<BlurEffect x:Key="BlurEffect" Radius="3" RenderingBias="Performance" KernelType="Box" />
|
||||
@@ -79,7 +79,7 @@
|
||||
</Border>
|
||||
</Border>
|
||||
<controls:SnowfallOverlay
|
||||
Visibility="{Binding ElementName=_this, Path=WintersdayMode, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Visibility="{Binding ElementName=_this, Path=WintersdayMode, Mode=OneWay, Converter={StaticResource BaseBooleanToVisibilityConverter}}"
|
||||
Opacity="0.4"
|
||||
BaseWind1="0.0247"
|
||||
BaseWind2="0.00427"
|
||||
@@ -102,7 +102,7 @@
|
||||
<Rectangle Fill="Transparent"
|
||||
MouseDown="Window_MouseLeftButtonDown"
|
||||
Grid.RowSpan="2"
|
||||
Grid.ColumnSpan="2"></Rectangle>
|
||||
Grid.ColumnSpan="2" />
|
||||
<buttons:MenuButton Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Background="Transparent"
|
||||
@@ -129,11 +129,11 @@
|
||||
ToolTip="Version Management"/>
|
||||
<buttons:MenuButton Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Opacity="0.6" Title=" - " FontSize="10" BorderBrush="Transparent" BorderThickness="0"
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BaseBooleanToVisibilityConverter}}"
|
||||
ToolTip="Running with Administrator Rights"/>
|
||||
<buttons:MenuButton Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Opacity="0.6" Title="[Admin]" FontSize="10" BorderBrush="Transparent" BorderThickness="0"
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BaseBooleanToVisibilityConverter}}"
|
||||
Clicked="AdminText_Clicked"
|
||||
ToolTip="Running with Administrator Rights"/>
|
||||
</WrapPanel>
|
||||
@@ -174,6 +174,25 @@
|
||||
Visibility="{Binding ElementName=_this, Path=IsShowingDropdown, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Click="SettingsButton_Clicked"
|
||||
ToolTip="Close Settings"/>
|
||||
<buttons:HighlightButton Height="30"
|
||||
Width="47"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Grid.Column="1"
|
||||
Margin="0, 0, 140, 0"
|
||||
Cursor="Arrow"
|
||||
Opacity="0.8"
|
||||
HighlightColor="White"
|
||||
ToolTip="Synchronize Settings"
|
||||
Clicked="SynchronizeButton_Click">
|
||||
<buttons:HighlightButton.ButtonContent>
|
||||
<Grid Height="30"
|
||||
Width="30">
|
||||
<glyphs:DownloadGlyph Height="20"
|
||||
Width="20" />
|
||||
</Grid>
|
||||
</buttons:HighlightButton.ButtonContent>
|
||||
</buttons:HighlightButton>
|
||||
<notifications:NotificationStackpanel
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
|
||||
@@ -8,12 +8,15 @@ using Daybreak.Services.Screenshots;
|
||||
using Daybreak.Services.Updater;
|
||||
using Daybreak.Views;
|
||||
using MahApps.Metro.Controls;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Core.Extensions;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
@@ -31,6 +34,7 @@ namespace Daybreak.Launch;
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class MainWindow : MetroWindow
|
||||
{
|
||||
private readonly IOptionsSynchronizationService optionsSynchronizationService;
|
||||
private readonly ISplashScreenService splashScreenService;
|
||||
private readonly IMenuServiceInitializer menuServiceInitializer;
|
||||
private readonly IViewManager viewManager;
|
||||
@@ -55,10 +59,13 @@ public partial class MainWindow : MetroWindow
|
||||
private bool blurBackground;
|
||||
[GenerateDependencyProperty]
|
||||
private bool wintersdayMode;
|
||||
[GenerateDependencyProperty]
|
||||
private bool settingsSynchronized;
|
||||
|
||||
public event EventHandler<MainWindow>? WindowParametersChanged;
|
||||
|
||||
public MainWindow(
|
||||
IOptionsSynchronizationService optionsSynchronizationService,
|
||||
ISplashScreenService splashScreenService,
|
||||
IMenuServiceInitializer menuServiceInitializer,
|
||||
IViewManager viewManager,
|
||||
@@ -69,6 +76,7 @@ public partial class MainWindow : MetroWindow
|
||||
ILiveOptions<LauncherOptions> launcherOptions,
|
||||
ILiveOptions<ThemeOptions> themeOptions)
|
||||
{
|
||||
this.optionsSynchronizationService = optionsSynchronizationService.ThrowIfNull();
|
||||
this.splashScreenService = splashScreenService.ThrowIfNull();
|
||||
this.menuServiceInitializer = menuServiceInitializer.ThrowIfNull();
|
||||
this.viewManager = viewManager.ThrowIfNull();
|
||||
@@ -83,7 +91,6 @@ public partial class MainWindow : MetroWindow
|
||||
this.IsRunningAsAdmin = this.privilegeManager.AdminPrivileges;
|
||||
this.ThemeOptionsChanged();
|
||||
this.SetupMenuService();
|
||||
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
@@ -110,6 +117,11 @@ public partial class MainWindow : MetroWindow
|
||||
this.viewManager.ShowView<LauncherView>();
|
||||
}
|
||||
|
||||
private void SynchronizeButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<SettingsSynchronizationView>();
|
||||
}
|
||||
|
||||
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton is not MouseButton.Left &&
|
||||
@@ -130,7 +142,7 @@ public partial class MainWindow : MetroWindow
|
||||
|
||||
private void SetupImageCycle()
|
||||
{
|
||||
TaskExtensions.RunPeriodicAsync(() => this.Dispatcher.Invoke(() => this.UpdateRandomImage()), TimeSpan.Zero, TimeSpan.FromSeconds(15), this.cancellationToken.Token);
|
||||
System.Extensions.TaskExtensions.RunPeriodicAsync(() => this.Dispatcher.Invoke(() => this.UpdateRandomImage()), TimeSpan.Zero, TimeSpan.FromSeconds(15), this.cancellationToken.Token);
|
||||
}
|
||||
|
||||
private async void UpdateRandomImage()
|
||||
@@ -153,69 +165,78 @@ public partial class MainWindow : MetroWindow
|
||||
|
||||
private void OpenDropdownMenu()
|
||||
{
|
||||
if (this.IsShowingDropdown)
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.IsShowingDropdown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.ToggleDropdownMenu();
|
||||
this.ToggleDropdownMenu();
|
||||
});
|
||||
}
|
||||
|
||||
private void CloseDropdownMenu()
|
||||
{
|
||||
if (!this.IsShowingDropdown)
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!this.IsShowingDropdown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.ToggleDropdownMenu();
|
||||
this.ToggleDropdownMenu();
|
||||
});
|
||||
}
|
||||
|
||||
private void ToggleDropdownMenu()
|
||||
{
|
||||
var button = this.IsShowingDropdown ?
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var button = this.IsShowingDropdown ?
|
||||
this.ClosingSettingsButton :
|
||||
this.OpeningSettingsButton;
|
||||
button.IsEnabled = false;
|
||||
var widthAnimation = new DoubleAnimation
|
||||
{
|
||||
From = this.IsShowingDropdown ?
|
||||
this.MenuContainer.ActualWidth :
|
||||
0,
|
||||
To = this.IsShowingDropdown ?
|
||||
0 :
|
||||
300,
|
||||
Duration = new Duration(TimeSpan.FromMilliseconds(200)),
|
||||
DecelerationRatio = 0.7
|
||||
};
|
||||
button.IsEnabled = false;
|
||||
var widthAnimation = new DoubleAnimation
|
||||
{
|
||||
From = this.IsShowingDropdown ?
|
||||
this.MenuContainer.ActualWidth :
|
||||
0,
|
||||
To = this.IsShowingDropdown ?
|
||||
0 :
|
||||
300,
|
||||
Duration = new Duration(TimeSpan.FromMilliseconds(200)),
|
||||
DecelerationRatio = 0.7
|
||||
};
|
||||
|
||||
var opacityAnimation = new DoubleAnimation
|
||||
{
|
||||
From = this.IsShowingDropdown ?
|
||||
this.MenuContainer.Opacity :
|
||||
0,
|
||||
To = this.IsShowingDropdown ?
|
||||
0 :
|
||||
1,
|
||||
Duration = new Duration(TimeSpan.FromMilliseconds(100)),
|
||||
DecelerationRatio = 0.7
|
||||
};
|
||||
var opacityAnimation = new DoubleAnimation
|
||||
{
|
||||
From = this.IsShowingDropdown ?
|
||||
this.MenuContainer.Opacity :
|
||||
0,
|
||||
To = this.IsShowingDropdown ?
|
||||
0 :
|
||||
1,
|
||||
Duration = new Duration(TimeSpan.FromMilliseconds(100)),
|
||||
DecelerationRatio = 0.7
|
||||
};
|
||||
|
||||
var storyBoard = new Storyboard();
|
||||
storyBoard.Children.Add(widthAnimation);
|
||||
Storyboard.SetTarget(widthAnimation, this.MenuContainer);
|
||||
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Grid.WidthProperty));
|
||||
storyBoard.Children.Add(opacityAnimation);
|
||||
Storyboard.SetTarget(opacityAnimation, this.MenuContainer);
|
||||
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(Grid.OpacityProperty));
|
||||
var storyBoard = new Storyboard();
|
||||
storyBoard.Children.Add(widthAnimation);
|
||||
Storyboard.SetTarget(widthAnimation, this.MenuContainer);
|
||||
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Grid.WidthProperty));
|
||||
storyBoard.Children.Add(opacityAnimation);
|
||||
Storyboard.SetTarget(opacityAnimation, this.MenuContainer);
|
||||
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(Grid.OpacityProperty));
|
||||
|
||||
storyBoard.Completed += (_, _) =>
|
||||
{
|
||||
button.IsEnabled = true;
|
||||
this.IsShowingDropdown = !this.IsShowingDropdown;
|
||||
};
|
||||
storyBoard.Completed += (_, _) =>
|
||||
{
|
||||
button.IsEnabled = true;
|
||||
this.IsShowingDropdown = !this.IsShowingDropdown;
|
||||
};
|
||||
|
||||
storyBoard.Begin();
|
||||
storyBoard.Begin();
|
||||
});
|
||||
}
|
||||
|
||||
private void CreditTextBox_MouseLeftButtonDown(object sender, EventArgs e)
|
||||
|
||||
@@ -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
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ 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; } = new();
|
||||
public List<Skill> Skills { get; set; } = new() { Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill };
|
||||
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];
|
||||
public string? SourceUrl { get; set; }
|
||||
}
|
||||
|
||||
@@ -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; } = [];
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ public sealed class GuildwarsIcon : IWikiEntity
|
||||
public static readonly GuildwarsIcon DungeonBoss = new() { Id = 302779, Name = "Dungeon Boss" };
|
||||
public static readonly GuildwarsIcon DungeonKey = new() { Id = 302777, Name = "Dungeon Key" };
|
||||
|
||||
public static readonly List<GuildwarsIcon> Icons = new()
|
||||
{
|
||||
public static readonly List<GuildwarsIcon> Icons =
|
||||
[
|
||||
ResurrectionShrine,
|
||||
Collector,
|
||||
AreaMap,
|
||||
@@ -34,7 +34,7 @@ public sealed class GuildwarsIcon : IWikiEntity
|
||||
DungeonKey,
|
||||
Flag,
|
||||
Person
|
||||
};
|
||||
];
|
||||
|
||||
public static bool TryParse(int id, out GuildwarsIcon icon)
|
||||
{
|
||||
|
||||
@@ -6,10 +6,10 @@ public sealed class InventoryData
|
||||
{
|
||||
public Bag? Backpack { get; init; }
|
||||
public Bag? BeltPouch { get; init; }
|
||||
public List<Bag?> Bags { get; init; } = new();
|
||||
public List<Bag?> Bags { get; init; } = [];
|
||||
public Bag? EquipmentPack { get; init; }
|
||||
public Bag? MaterialStorage { get; init; }
|
||||
public Bag? UnclaimedItems { get; init; }
|
||||
public List<Bag?> StoragePanes { get; init; } = new();
|
||||
public List<Bag?> StoragePanes { get; init; } = [];
|
||||
public Bag? EquippedItems { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using SharpNav;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Models.Guildwars;
|
||||
|
||||
public sealed class PathingData
|
||||
{
|
||||
public List<Trapezoid> Trapezoids { get; init; } = new();
|
||||
public List<List<int>> ComputedPathingMaps { get; init; } = new();
|
||||
public List<List<int>> OriginalPathingMaps { get; init; } = new();
|
||||
public List<List<int>> OriginalAdjacencyList { get; init; } = new();
|
||||
public List<List<int>> ComputedAdjacencyList { get; init; } = new();
|
||||
public NavMesh? NavMesh { get; init; }
|
||||
public List<Trapezoid> Trapezoids { get; init; } = [];
|
||||
public List<List<int>> OriginalPathingMaps { get; init; } = [];
|
||||
public List<List<int>> OriginalAdjacencyList { get; init; } = [];
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:W/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Warrior",
|
||||
PrimaryAttribute = Attribute.Strength,
|
||||
Attributes = new List<Attribute> { Attribute.AxeMastery, Attribute.HammerMastery, Attribute.Swordsmanship, Attribute.Tactics }
|
||||
Attributes = [Attribute.AxeMastery, Attribute.HammerMastery, Attribute.Swordsmanship, Attribute.Tactics]
|
||||
};
|
||||
public static readonly Profession Ranger = new()
|
||||
{
|
||||
@@ -28,7 +28,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:R/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Ranger",
|
||||
PrimaryAttribute = Attribute.Expertise,
|
||||
Attributes = new List<Attribute> { Attribute.BeastMastery, Attribute.Marksmanship, Attribute.WildernessSurvival }
|
||||
Attributes = [Attribute.BeastMastery, Attribute.Marksmanship, Attribute.WildernessSurvival]
|
||||
};
|
||||
public static readonly Profession Monk = new()
|
||||
{
|
||||
@@ -38,7 +38,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:Mo/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Monk",
|
||||
PrimaryAttribute = Attribute.DivineFavor,
|
||||
Attributes = new List<Attribute> { Attribute.HealingPrayers, Attribute.SmitingPrayers, Attribute.ProtectionPrayers }
|
||||
Attributes = [Attribute.HealingPrayers, Attribute.SmitingPrayers, Attribute.ProtectionPrayers]
|
||||
};
|
||||
public static readonly Profession Necromancer = new()
|
||||
{
|
||||
@@ -48,7 +48,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:N/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Necromancer",
|
||||
PrimaryAttribute = Attribute.SoulReaping,
|
||||
Attributes = new List<Attribute> { Attribute.Curses, Attribute.BloodMagic, Attribute.DeathMagic }
|
||||
Attributes = [Attribute.Curses, Attribute.BloodMagic, Attribute.DeathMagic]
|
||||
};
|
||||
public static readonly Profession Mesmer = new()
|
||||
{
|
||||
@@ -58,7 +58,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:Me/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Mesmer",
|
||||
PrimaryAttribute = Attribute.FastCasting,
|
||||
Attributes = new List<Attribute> { Attribute.DominationMagic, Attribute.IllusionMagic, Attribute.InspirationMagic }
|
||||
Attributes = [Attribute.DominationMagic, Attribute.IllusionMagic, Attribute.InspirationMagic]
|
||||
};
|
||||
public static readonly Profession Elementalist = new()
|
||||
{
|
||||
@@ -68,7 +68,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:E/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Elementalist",
|
||||
PrimaryAttribute = Attribute.EnergyStorage,
|
||||
Attributes = new List<Attribute> { Attribute.AirMagic, Attribute.EarthMagic, Attribute.FireMagic, Attribute.WaterMagic }
|
||||
Attributes = [Attribute.AirMagic, Attribute.EarthMagic, Attribute.FireMagic, Attribute.WaterMagic]
|
||||
};
|
||||
public static readonly Profession Assassin = new()
|
||||
{
|
||||
@@ -78,7 +78,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:A/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Assassin",
|
||||
PrimaryAttribute = Attribute.CriticalStrikes,
|
||||
Attributes = new List<Attribute> { Attribute.DaggerMastery, Attribute.DeadlyArts, Attribute.ShadowArts }
|
||||
Attributes = [Attribute.DaggerMastery, Attribute.DeadlyArts, Attribute.ShadowArts]
|
||||
};
|
||||
public static readonly Profession Ritualist = new()
|
||||
{
|
||||
@@ -88,7 +88,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:Rt/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Ritualist",
|
||||
PrimaryAttribute = Attribute.SpawningPower,
|
||||
Attributes = new List<Attribute> { Attribute.ChannelingMagic, Attribute.Communing, Attribute.RestorationMagic }
|
||||
Attributes = [Attribute.ChannelingMagic, Attribute.Communing, Attribute.RestorationMagic]
|
||||
};
|
||||
public static readonly Profession Paragon = new()
|
||||
{
|
||||
@@ -98,7 +98,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:P/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Paragon",
|
||||
PrimaryAttribute = Attribute.Leadership,
|
||||
Attributes = new List<Attribute> { Attribute.Command, Attribute.Motivation, Attribute.SpearMastery }
|
||||
Attributes = [Attribute.Command, Attribute.Motivation, Attribute.SpearMastery]
|
||||
};
|
||||
public static readonly Profession Dervish = new()
|
||||
{
|
||||
@@ -108,7 +108,7 @@ public sealed class Profession : IWikiEntity
|
||||
BuildsUrl = "https://gwpvx.fandom.com/wiki/Special:PrefixIndex/Build:D/",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Dervish",
|
||||
PrimaryAttribute = Attribute.Mysticism,
|
||||
Attributes = new List<Attribute> { Attribute.EarthPrayers, Attribute.ScytheMastery, Attribute.WindPrayers }
|
||||
Attributes = [Attribute.EarthPrayers, Attribute.ScytheMastery, Attribute.WindPrayers]
|
||||
};
|
||||
public static IEnumerable<Profession> Professions = new List<Profession>
|
||||
{
|
||||
@@ -169,7 +169,7 @@ public sealed class Profession : IWikiEntity
|
||||
public string? Name { get; init; }
|
||||
public int Id { get; set; }
|
||||
public Attribute? PrimaryAttribute { get; private set; }
|
||||
public List<Attribute> Attributes { get; private set; } = new List<Attribute>();
|
||||
public List<Attribute> Attributes { get; private set; } = [];
|
||||
private Profession()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -10,51 +10,51 @@ namespace Daybreak.Models.Guildwars;
|
||||
public sealed class Title : IWikiEntity
|
||||
{
|
||||
public static readonly Title None = new() { Id = 0xFF, };
|
||||
public static readonly Title Hero = new() { Id = 0, Name = "Hero", WikiUrl = "https://wiki.guildwars.com/wiki/Hero_(title)", Tiers = new List<string> { "Hero", "Fierce Hero", "Mighty Hero", "Deadly Hero", "Terrifying Hero", "Conquering Hero", "Subjugating Hero", "Vanquishing Hero", "Renowed Hero", "Illustrious Hero", "Eminent Hero", "King's Hero", "Emperor's Hero", "Balthazar's Hero", "Legendary Hero" } };
|
||||
public static readonly Title TyrianCartographer = new() { Id = 1, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = new List<string> { "Tyrian Explorer", "Tyrian Pathfinder", "Tyrian Trailblazer", "Tyrian Cartographer", "Tyrian Master Cartographer", "Tyrian Grandmaster Cartographer" } };
|
||||
public static readonly Title CanthanCartographer = new() { Id = 2, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = new List<string> { "Canthan Explorer", "Canthan Pathfinder", "Canthan Trailblazer", "Canthan Cartographer", "Canthan Master Cartographer", "Canthan Grandmaster Cartographer" } };
|
||||
public static readonly Title Gladiator = new() { Id = 3, Name = "Gladiator", WikiUrl = "https://wiki.guildwars.com/wiki/Gladiator", Tiers = new List<string> { "Gladiator", "Fierce Gladiator", "Mighty Gladiator", "Deadly Gladiator", "Terrifying Gladiator", "Conquering Gladiator", "Subjugating Gladiator", "Vanquishing Gladiator", "King's Gladiator", "Emperor's Gladiator", "Balthazar's Gladiator", "Legendary Gladiator" } };
|
||||
public static readonly Title Champion = new() { Id = 4, Name = "Champion", WikiUrl = "https://wiki.guildwars.com/wiki/Champion", Tiers = new List<string> { "Champion", "Fierce Champion", "Mighty Champion", "Deadly Champion", "Terrifying Champion", "Conquering Champion", "Subjugating Champion", "Vanquishing Champion", "King's Champion", "Emperor's Champion", "Balthazar's Champion", "Legendary Champion" } };
|
||||
public static readonly Title Kurzick = new() { Id = 5, Name = "Faction Allegiance", WikiUrl = "https://wiki.guildwars.com/wiki/Allegiance_rank", Tiers = new List<string> { "Kurzick Supporter", "Friend of the Kurzicks", "Companion of the Kurzicks", "Ally of the Kurzicks", "Sentinel of the Kurzicks", "Steward of the Kurzicks", "Defender of the Kurzicks", "Warden of the Kurzicks", "Bastion of the Kurzicks", "Champion of the Kurzicks", "Hero of the Kurzicks", "Savior of the Kurzicks" } };
|
||||
public static readonly Title Luxon = new() { Id = 6, Name = "Faction Allegiance", WikiUrl = "https://wiki.guildwars.com/wiki/Allegiance_rank", Tiers = new List<string> { "Luxon Supporter", "Friend of the Kurzicks", "Companion of the Luxons", "Ally of the Luxons", "Sentinel of the Luxons", "Steward of the Luxons", "Defender of the Luxons", "Warden of the Luxons", "Bastion of the Luxons", "Champion of the Luxons", "Hero of the Luxons", "Savior of the Luxons" } };
|
||||
public static readonly Title Drunkard = new() { Id = 7, Name = "Drunkard", WikiUrl = "https://wiki.guildwars.com/wiki/Drunkard", Tiers = new List<string> { "Drunkard", "Incorrigible Ale-Hound" } };
|
||||
public static readonly Title Survivor = new() { Id = 9, Name = "Survivor", WikiUrl = "https://wiki.guildwars.com/wiki/Survivor", Tiers = new List<string> { "Survivor", "Indomitable Survivor", "Legendary Survivor" } };
|
||||
public static readonly Title KindOfABigDeal = new() { Id = 10, Name = "Kind of a Big Deal", WikiUrl = "https://wiki.guildwars.com/wiki/Kind_of_a_Big_Deal", Tiers = new List<string> { "Kind Of A Big Deal", "People Know Me", "I'm Very Important", "I Have Many Leather-Bound Books", "My Guild Hall Smells of Rich Mahogany", "God Walking Amongst Mere Mortals" } };
|
||||
public static readonly Title ProtectorTyria = new() { Id = 13, Name = "Protector of Tyria", WikiUrl = "https://wiki.guildwars.com/wiki/Protector", Tiers = new List<string> { "Protector of Tyria" } };
|
||||
public static readonly Title ProtectorCantha = new() { Id = 14, Name = "Protector of Cantha", WikiUrl = "https://wiki.guildwars.com/wiki/Protector", Tiers = new List<string> { "Protector of Cantha" } };
|
||||
public static readonly Title Lucky = new() { Id = 15, Name = "Lucky", WikiUrl = "https://wiki.guildwars.com/wiki/Lucky_and_Unlucky", Tiers = new List<string> { "Charmed", "Lucky", "Favored", "Prosperous", "Golden", "Blessed by Fate" } };
|
||||
public static readonly Title Unlucky = new() { Id = 16, Name = "Unlucky", WikiUrl = "https://wiki.guildwars.com/wiki/Lucky_and_Unlucky", Tiers = new List<string> { "Hapless", "Unlucky", "Unfavored", "Tragic", "Wretched", "Jinxed", "Cursed by Fate" } };
|
||||
public static readonly Title Sunspear = new() { Id = 17, Name = "Sunspear", WikiUrl = "https://wiki.guildwars.com/wiki/Sunspear_rank", Tiers = new List<string> { "Sunspear Sergeant", "Sunspear Master Sergeant", "Second Spear", "First Spear", "Sunspear Captain", "Sunspear Commander", "Sunspear General", "Sunspear Castellan", "Spearmarshal", "Legendary Spearmarshal" } };
|
||||
public static readonly Title ElonianCartographer = new() { Id = 18, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = new List<string> { "Elonian Explorer", "Elonian Pathfinder", "Elonian Trailblazer", "Elonian Cartographer", "Elonian Master Cartographer", "Elonian Grandmaster Cartographer" } };
|
||||
public static readonly Title ProtectorElona = new() { Id = 19, Name = "Protector of Elona", WikiUrl = "https://wiki.guildwars.com/wiki/Protector", Tiers = new List<string> { "Protector of Elona" } };
|
||||
public static readonly Title Lightbringer = new() { Id = 20, Name = "Lightbringer", WikiUrl = "https://wiki.guildwars.com/wiki/Lightbringer_rank", Tiers = new List<string> { "Lightbringer", "Adept Lightbringer", "Brave Lightbringer", "Mighty Lightbringer", "Conquering Lightbringer", "Vanquishing Lightbringer", "Revered Lightbringer", "Holy Lightbringer" } };
|
||||
public static readonly Title LegendaryDefenderOfAscalon = new() { Id = 21, Name = "Defender of Ascalon", WikiUrl = "https://wiki.guildwars.com/wiki/Defender_of_Ascalon", Tiers = new List<string> { "Legendary Defender of Ascalon" } };
|
||||
public static readonly Title Commander = new() { Id = 22, Name = "Commander", WikiUrl = "https://wiki.guildwars.com/wiki/Commander", Tiers = new List<string> { "Commander", "Victorious Commander", "Triumphant Commander", "Keen Commander", "Battle Commander", "Field Commander", "Lieutenant Commander", "Wing Commander", "Cobra Commander", "Supreme Commander", "Master And Commander", "Legendary Commander" } };
|
||||
public static readonly Title Gamer = new() { Id = 23, Name = "Gamer", WikiUrl = "https://wiki.guildwars.com/wiki/Gamer", Tiers = new List<string> { "Skillz", "Pro Skillz", "Numchuck Skillz", "Mad Skillz", "Über Micro Skillz", "Gosu Skillz", "1337 Skillz", "iddqd Skillz", "T3h Haxz0rz Skillz", "Pure Pwnage Skillz", "These skillz go to", "Real Ultimate Power Skillz" } };
|
||||
public static readonly Title SkillHunterTyria = new() { Id = 24, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = new List<string> { "Tyrian Elite Skill Hunter" } };
|
||||
public static readonly Title VanquisherTyria = new() { Id = 25, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = new List<string> { "Tyrian Vanquisher" } };
|
||||
public static readonly Title SkillHunterCantha = new() { Id = 26, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = new List<string> { "Canthan Elite Skill Hunter" } };
|
||||
public static readonly Title VanquisherCantha = new() { Id = 27, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = new List<string> { "Canthan Vanquisher" } };
|
||||
public static readonly Title SkillHunterElona = new() { Id = 28, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = new List<string> { "Elonian Elite Skill Hunter" } };
|
||||
public static readonly Title VanquisherElona = new() { Id = 29, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = new List<string> { "Elonian Vanquisher" } };
|
||||
public static readonly Title LegendaryCartographer = new() { Id = 30, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = new List<string> { "Legendary Cartographer" } };
|
||||
public static readonly Title LegendaryGuardian = new() { Id = 31, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = new List<string> { "Legendary Guardian" } };
|
||||
public static readonly Title LegendarySkillHunter = new() { Id = 32, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = new List<string> { "Legendary Skill Hunter" } };
|
||||
public static readonly Title LegendaryVanquisher = new() { Id = 33, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = new List<string> { "Legendary Vanquisher" } };
|
||||
public static readonly Title SweetTooth = new() { Id = 34, Name = "Sweet Tooth", WikiUrl = "https://wiki.guildwars.com/wiki/Sweet_Tooth", Tiers = new List<string> { "Sweet Tooth", "Connoisseur of Confectionaries" } };
|
||||
public static readonly Title GuardianTyria = new() { Id = 35, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = new List<string> { "Guardian of Tyria" } };
|
||||
public static readonly Title GuardianCantha = new() { Id = 36, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = new List<string> { "Guardian of Cantha" } };
|
||||
public static readonly Title GuardianElona = new() { Id = 37, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = new List<string> { "Guardian of Elona" } };
|
||||
public static readonly Title Asura = new() { Id = 38, Name = "Asura", WikiUrl = "https://wiki.guildwars.com/wiki/Asura_rank", Tiers = new List<string> { "Not Too Smelly", "Not Too Dopey", "Not Too Clumsy", "Not Too Boring", "Not Too Annoying", "Not Too Grumpy", "Not Too Silly", "Not Too Lazy", "Not Too Foolish", "Not Too Shabby" } };
|
||||
public static readonly Title Deldrimor = new() { Id = 39, Name = "Deldrimor", WikiUrl = "https://wiki.guildwars.com/wiki/Deldrimor_rank", Tiers = new List<string> { "Delver", "Stout Delver", "Gutsy Delver", "Risky Delver", "Bold Delver", "Daring Delver", "Adventurous Delver", "Courageous Delver", "Epic Delver", "Legendary Delver" } };
|
||||
public static readonly Title EbonVanguard = new() { Id = 40, Name = "Ebon Vanguard", WikiUrl = "https://wiki.guildwars.com/wiki/Ebon_Vanguard_rank", Tiers = new List<string> { "Agent", "Covert Agent", "Stealth Agent", "Mysterious Agent", "Shadow Agent", "Underground Agent", "Special Agent", "Valued Agent", "Superior Agent", "Secret Agent" } };
|
||||
public static readonly Title Norn = new() { Id = 41, Name = "Norn", WikiUrl = "https://wiki.guildwars.com/wiki/Norn_rank", Tiers = new List<string> { "Slayer of Imps", "Slayer of Beasts", "Slayer of Nightmares", "Slayer of Giants", "Slayer of Wurms", "Slayer of Demons", "Slayer of Heroes", "Slayer of Champions", "Slayer of Hordes", "Slayer of All" } };
|
||||
public static readonly Title MasterOfTheNorth = new() { Id = 42, Name = "Master of the North", WikiUrl = "https://wiki.guildwars.com/wiki/Master_of_the_North", Tiers = new List<string> { "Adventurer of the North", "Pioneer of the North", "Veteran of the North", "Conqueror of the North", "Master of the North", "Legendary Master of the North" } };
|
||||
public static readonly Title PartyAnimal = new() { Id = 43, Name = "Party Animal", WikiUrl = "https://wiki.guildwars.com/wiki/Party_Animal", Tiers = new List<string> { "Party Animal", "Life of the Party" } };
|
||||
public static readonly Title Zaishen = new() { Id = 44, Name = "Zaishen", WikiUrl = "https://wiki.guildwars.com/wiki/Zaishen_rank", Tiers = new List<string> { "Zaishen Supporter", "Friend of the Zaishen", "Companion of the Zaishen", "Ally of the Zaishen", "Sentinel of the Zaishen", "Steward of the Zaishen", "Defender of the Zaishen", "Warden of the Zaishen", "Bastion of the Zaishen", "Champion of the Zaishen", "Hero of the Zaishen", "Legendary Hero of the Zaishen" } };
|
||||
public static readonly Title TreasureHunter = new() { Id = 45, Name = "Treasure Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Treasure_Hunter", Tiers = new List<string> { "Treasure Hunter", "Adept Treasure Hunter", "Advanced Treasure Hunter", "Expert Treasure Hunter", "Elite Treasure Hunter", "Master Treasure Hunter", "Grandmaster Treasure Hunter" } };
|
||||
public static readonly Title Wisdom = new() { Id = 46, Name = "Wisdom", WikiUrl = "https://wiki.guildwars.com/wiki/Wisdom", Tiers = new List<string> { "Seeker of Wisdom", "Collector of Wisdom", "Devotee of Wisdom", "Devourer of Wisdom", "Font of Wisdom", "Oracle of Wisdom", "Source of Wisdom" } };
|
||||
public static readonly Title Codex = new() { Id = 47, Name = "Codex", WikiUrl = "https://wiki.guildwars.com/wiki/Codex_Title", Tiers = new List<string> { "Codex Initiate", "Codex Acolyte", "Codex Disciple", "Codex Zealot", "Codex Stalwart", "Codex Adept", "Codex Exemplar", "Codex Prodigy", "Codex Champion", "Codex Paragon", "Codex Master", "Codex Grandmaster" } };
|
||||
public static readonly Title Hero = new() { Id = 0, Name = "Hero", WikiUrl = "https://wiki.guildwars.com/wiki/Hero_(title)", Tiers = ["Hero", "Fierce Hero", "Mighty Hero", "Deadly Hero", "Terrifying Hero", "Conquering Hero", "Subjugating Hero", "Vanquishing Hero", "Renowed Hero", "Illustrious Hero", "Eminent Hero", "King's Hero", "Emperor's Hero", "Balthazar's Hero", "Legendary Hero"] };
|
||||
public static readonly Title TyrianCartographer = new() { Id = 1, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = ["Tyrian Explorer", "Tyrian Pathfinder", "Tyrian Trailblazer", "Tyrian Cartographer", "Tyrian Master Cartographer", "Tyrian Grandmaster Cartographer"] };
|
||||
public static readonly Title CanthanCartographer = new() { Id = 2, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = ["Canthan Explorer", "Canthan Pathfinder", "Canthan Trailblazer", "Canthan Cartographer", "Canthan Master Cartographer", "Canthan Grandmaster Cartographer"] };
|
||||
public static readonly Title Gladiator = new() { Id = 3, Name = "Gladiator", WikiUrl = "https://wiki.guildwars.com/wiki/Gladiator", Tiers = ["Gladiator", "Fierce Gladiator", "Mighty Gladiator", "Deadly Gladiator", "Terrifying Gladiator", "Conquering Gladiator", "Subjugating Gladiator", "Vanquishing Gladiator", "King's Gladiator", "Emperor's Gladiator", "Balthazar's Gladiator", "Legendary Gladiator"] };
|
||||
public static readonly Title Champion = new() { Id = 4, Name = "Champion", WikiUrl = "https://wiki.guildwars.com/wiki/Champion", Tiers = ["Champion", "Fierce Champion", "Mighty Champion", "Deadly Champion", "Terrifying Champion", "Conquering Champion", "Subjugating Champion", "Vanquishing Champion", "King's Champion", "Emperor's Champion", "Balthazar's Champion", "Legendary Champion"] };
|
||||
public static readonly Title Kurzick = new() { Id = 5, Name = "Faction Allegiance", WikiUrl = "https://wiki.guildwars.com/wiki/Allegiance_rank", Tiers = ["Kurzick Supporter", "Friend of the Kurzicks", "Companion of the Kurzicks", "Ally of the Kurzicks", "Sentinel of the Kurzicks", "Steward of the Kurzicks", "Defender of the Kurzicks", "Warden of the Kurzicks", "Bastion of the Kurzicks", "Champion of the Kurzicks", "Hero of the Kurzicks", "Savior of the Kurzicks"] };
|
||||
public static readonly Title Luxon = new() { Id = 6, Name = "Faction Allegiance", WikiUrl = "https://wiki.guildwars.com/wiki/Allegiance_rank", Tiers = ["Luxon Supporter", "Friend of the Kurzicks", "Companion of the Luxons", "Ally of the Luxons", "Sentinel of the Luxons", "Steward of the Luxons", "Defender of the Luxons", "Warden of the Luxons", "Bastion of the Luxons", "Champion of the Luxons", "Hero of the Luxons", "Savior of the Luxons"] };
|
||||
public static readonly Title Drunkard = new() { Id = 7, Name = "Drunkard", WikiUrl = "https://wiki.guildwars.com/wiki/Drunkard", Tiers = ["Drunkard", "Incorrigible Ale-Hound"] };
|
||||
public static readonly Title Survivor = new() { Id = 9, Name = "Survivor", WikiUrl = "https://wiki.guildwars.com/wiki/Survivor", Tiers = ["Survivor", "Indomitable Survivor", "Legendary Survivor"] };
|
||||
public static readonly Title KindOfABigDeal = new() { Id = 10, Name = "Kind of a Big Deal", WikiUrl = "https://wiki.guildwars.com/wiki/Kind_of_a_Big_Deal", Tiers = ["Kind Of A Big Deal", "People Know Me", "I'm Very Important", "I Have Many Leather-Bound Books", "My Guild Hall Smells of Rich Mahogany", "God Walking Amongst Mere Mortals"] };
|
||||
public static readonly Title ProtectorTyria = new() { Id = 13, Name = "Protector of Tyria", WikiUrl = "https://wiki.guildwars.com/wiki/Protector", Tiers = ["Protector of Tyria"] };
|
||||
public static readonly Title ProtectorCantha = new() { Id = 14, Name = "Protector of Cantha", WikiUrl = "https://wiki.guildwars.com/wiki/Protector", Tiers = ["Protector of Cantha"] };
|
||||
public static readonly Title Lucky = new() { Id = 15, Name = "Lucky", WikiUrl = "https://wiki.guildwars.com/wiki/Lucky_and_Unlucky", Tiers = ["Charmed", "Lucky", "Favored", "Prosperous", "Golden", "Blessed by Fate"] };
|
||||
public static readonly Title Unlucky = new() { Id = 16, Name = "Unlucky", WikiUrl = "https://wiki.guildwars.com/wiki/Lucky_and_Unlucky", Tiers = ["Hapless", "Unlucky", "Unfavored", "Tragic", "Wretched", "Jinxed", "Cursed by Fate"] };
|
||||
public static readonly Title Sunspear = new() { Id = 17, Name = "Sunspear", WikiUrl = "https://wiki.guildwars.com/wiki/Sunspear_rank", Tiers = ["Sunspear Sergeant", "Sunspear Master Sergeant", "Second Spear", "First Spear", "Sunspear Captain", "Sunspear Commander", "Sunspear General", "Sunspear Castellan", "Spearmarshal", "Legendary Spearmarshal"] };
|
||||
public static readonly Title ElonianCartographer = new() { Id = 18, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = ["Elonian Explorer", "Elonian Pathfinder", "Elonian Trailblazer", "Elonian Cartographer", "Elonian Master Cartographer", "Elonian Grandmaster Cartographer"] };
|
||||
public static readonly Title ProtectorElona = new() { Id = 19, Name = "Protector of Elona", WikiUrl = "https://wiki.guildwars.com/wiki/Protector", Tiers = ["Protector of Elona"] };
|
||||
public static readonly Title Lightbringer = new() { Id = 20, Name = "Lightbringer", WikiUrl = "https://wiki.guildwars.com/wiki/Lightbringer_rank", Tiers = ["Lightbringer", "Adept Lightbringer", "Brave Lightbringer", "Mighty Lightbringer", "Conquering Lightbringer", "Vanquishing Lightbringer", "Revered Lightbringer", "Holy Lightbringer"] };
|
||||
public static readonly Title LegendaryDefenderOfAscalon = new() { Id = 21, Name = "Defender of Ascalon", WikiUrl = "https://wiki.guildwars.com/wiki/Defender_of_Ascalon", Tiers = ["Legendary Defender of Ascalon"] };
|
||||
public static readonly Title Commander = new() { Id = 22, Name = "Commander", WikiUrl = "https://wiki.guildwars.com/wiki/Commander", Tiers = ["Commander", "Victorious Commander", "Triumphant Commander", "Keen Commander", "Battle Commander", "Field Commander", "Lieutenant Commander", "Wing Commander", "Cobra Commander", "Supreme Commander", "Master And Commander", "Legendary Commander"] };
|
||||
public static readonly Title Gamer = new() { Id = 23, Name = "Gamer", WikiUrl = "https://wiki.guildwars.com/wiki/Gamer", Tiers = ["Skillz", "Pro Skillz", "Numchuck Skillz", "Mad Skillz", "Über Micro Skillz", "Gosu Skillz", "1337 Skillz", "iddqd Skillz", "T3h Haxz0rz Skillz", "Pure Pwnage Skillz", "These skillz go to", "Real Ultimate Power Skillz"] };
|
||||
public static readonly Title SkillHunterTyria = new() { Id = 24, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = ["Tyrian Elite Skill Hunter"] };
|
||||
public static readonly Title VanquisherTyria = new() { Id = 25, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = ["Tyrian Vanquisher"] };
|
||||
public static readonly Title SkillHunterCantha = new() { Id = 26, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = ["Canthan Elite Skill Hunter"] };
|
||||
public static readonly Title VanquisherCantha = new() { Id = 27, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = ["Canthan Vanquisher"] };
|
||||
public static readonly Title SkillHunterElona = new() { Id = 28, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = ["Elonian Elite Skill Hunter"] };
|
||||
public static readonly Title VanquisherElona = new() { Id = 29, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = ["Elonian Vanquisher"] };
|
||||
public static readonly Title LegendaryCartographer = new() { Id = 30, Name = "Cartographer", WikiUrl = "https://wiki.guildwars.com/wiki/Cartographer", Tiers = ["Legendary Cartographer"] };
|
||||
public static readonly Title LegendaryGuardian = new() { Id = 31, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = ["Legendary Guardian"] };
|
||||
public static readonly Title LegendarySkillHunter = new() { Id = 32, Name = "Skill Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Skill_Hunter", Tiers = ["Legendary Skill Hunter"] };
|
||||
public static readonly Title LegendaryVanquisher = new() { Id = 33, Name = "Vanquisher", WikiUrl = "https://wiki.guildwars.com/wiki/Vanquisher", Tiers = ["Legendary Vanquisher"] };
|
||||
public static readonly Title SweetTooth = new() { Id = 34, Name = "Sweet Tooth", WikiUrl = "https://wiki.guildwars.com/wiki/Sweet_Tooth", Tiers = ["Sweet Tooth", "Connoisseur of Confectionaries"] };
|
||||
public static readonly Title GuardianTyria = new() { Id = 35, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = ["Guardian of Tyria"] };
|
||||
public static readonly Title GuardianCantha = new() { Id = 36, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = ["Guardian of Cantha"] };
|
||||
public static readonly Title GuardianElona = new() { Id = 37, Name = "Guardian", WikiUrl = "https://wiki.guildwars.com/wiki/Guardian_(title)", Tiers = ["Guardian of Elona"] };
|
||||
public static readonly Title Asura = new() { Id = 38, Name = "Asura", WikiUrl = "https://wiki.guildwars.com/wiki/Asura_rank", Tiers = ["Not Too Smelly", "Not Too Dopey", "Not Too Clumsy", "Not Too Boring", "Not Too Annoying", "Not Too Grumpy", "Not Too Silly", "Not Too Lazy", "Not Too Foolish", "Not Too Shabby"] };
|
||||
public static readonly Title Deldrimor = new() { Id = 39, Name = "Deldrimor", WikiUrl = "https://wiki.guildwars.com/wiki/Deldrimor_rank", Tiers = ["Delver", "Stout Delver", "Gutsy Delver", "Risky Delver", "Bold Delver", "Daring Delver", "Adventurous Delver", "Courageous Delver", "Epic Delver", "Legendary Delver"] };
|
||||
public static readonly Title EbonVanguard = new() { Id = 40, Name = "Ebon Vanguard", WikiUrl = "https://wiki.guildwars.com/wiki/Ebon_Vanguard_rank", Tiers = ["Agent", "Covert Agent", "Stealth Agent", "Mysterious Agent", "Shadow Agent", "Underground Agent", "Special Agent", "Valued Agent", "Superior Agent", "Secret Agent"] };
|
||||
public static readonly Title Norn = new() { Id = 41, Name = "Norn", WikiUrl = "https://wiki.guildwars.com/wiki/Norn_rank", Tiers = ["Slayer of Imps", "Slayer of Beasts", "Slayer of Nightmares", "Slayer of Giants", "Slayer of Wurms", "Slayer of Demons", "Slayer of Heroes", "Slayer of Champions", "Slayer of Hordes", "Slayer of All"] };
|
||||
public static readonly Title MasterOfTheNorth = new() { Id = 42, Name = "Master of the North", WikiUrl = "https://wiki.guildwars.com/wiki/Master_of_the_North", Tiers = ["Adventurer of the North", "Pioneer of the North", "Veteran of the North", "Conqueror of the North", "Master of the North", "Legendary Master of the North"] };
|
||||
public static readonly Title PartyAnimal = new() { Id = 43, Name = "Party Animal", WikiUrl = "https://wiki.guildwars.com/wiki/Party_Animal", Tiers = ["Party Animal", "Life of the Party"] };
|
||||
public static readonly Title Zaishen = new() { Id = 44, Name = "Zaishen", WikiUrl = "https://wiki.guildwars.com/wiki/Zaishen_rank", Tiers = ["Zaishen Supporter", "Friend of the Zaishen", "Companion of the Zaishen", "Ally of the Zaishen", "Sentinel of the Zaishen", "Steward of the Zaishen", "Defender of the Zaishen", "Warden of the Zaishen", "Bastion of the Zaishen", "Champion of the Zaishen", "Hero of the Zaishen", "Legendary Hero of the Zaishen"] };
|
||||
public static readonly Title TreasureHunter = new() { Id = 45, Name = "Treasure Hunter", WikiUrl = "https://wiki.guildwars.com/wiki/Treasure_Hunter", Tiers = ["Treasure Hunter", "Adept Treasure Hunter", "Advanced Treasure Hunter", "Expert Treasure Hunter", "Elite Treasure Hunter", "Master Treasure Hunter", "Grandmaster Treasure Hunter"] };
|
||||
public static readonly Title Wisdom = new() { Id = 46, Name = "Wisdom", WikiUrl = "https://wiki.guildwars.com/wiki/Wisdom", Tiers = ["Seeker of Wisdom", "Collector of Wisdom", "Devotee of Wisdom", "Devourer of Wisdom", "Font of Wisdom", "Oracle of Wisdom", "Source of Wisdom"] };
|
||||
public static readonly Title Codex = new() { Id = 47, Name = "Codex", WikiUrl = "https://wiki.guildwars.com/wiki/Codex_Title", Tiers = ["Codex Initiate", "Codex Acolyte", "Codex Disciple", "Codex Zealot", "Codex Stalwart", "Codex Adept", "Codex Exemplar", "Codex Prodigy", "Codex Champion", "Codex Paragon", "Codex Master", "Codex Grandmaster"] };
|
||||
|
||||
public static readonly IEnumerable<Title> Titles = new List<Title>
|
||||
{
|
||||
|
||||
@@ -5,6 +5,6 @@ using System.Windows.Media;
|
||||
namespace Daybreak.Models;
|
||||
public sealed class PathfindingCache
|
||||
{
|
||||
public List<PathfindingResponse> PathfindingResponses { get; set; } = new List<PathfindingResponse>();
|
||||
public List<Color> Colors { get; set; } = new List<Color>();
|
||||
public List<PathfindingResponse> PathfindingResponses { get; set; } = [];
|
||||
public List<Color> Colors { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Daybreak.Converters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Models.Trade;
|
||||
|
||||
[JsonConverter(typeof(TradeAlertConverter))]
|
||||
public interface ITradeAlert
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Daybreak.Services.TradeChat.Models;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Models.Trade;
|
||||
public sealed class QuoteAlert : ITradeAlert
|
||||
{
|
||||
public string Id { get; set; } = Guid.NewGuid().ToString();
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public int ItemId { get; set; }
|
||||
public TraderQuoteType TraderQuoteType { get; set; }
|
||||
|
||||
public int UpperPriceTarget { get; set; }
|
||||
public bool UpperPriceTargetEnabled { get; set; }
|
||||
|
||||
public int LowerPriceTarget { get; set; }
|
||||
public bool LowerPriceTargetEnabled { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Models.Trade;
|
||||
|
||||
public sealed class TradeAlert
|
||||
public sealed class TradeAlert : ITradeAlert
|
||||
{
|
||||
public string Id { get; set; } = Guid.NewGuid().ToString();
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
@@ -7,7 +7,9 @@ namespace Daybreak.Models.Versioning;
|
||||
|
||||
public sealed class Version : IEquatable<Version>, IComparable<Version>
|
||||
{
|
||||
private List<VersionToken> parts = new();
|
||||
public static readonly Version Zero = new("0");
|
||||
|
||||
private List<VersionToken> parts = [];
|
||||
|
||||
public bool HasPrefix { get; set; }
|
||||
public IEnumerable<VersionToken> VersionTokens { get => this.parts; }
|
||||
@@ -190,7 +192,7 @@ public sealed class Version : IEquatable<Version>, IComparable<Version>
|
||||
tokens[0] = tokens[0][1..];
|
||||
}
|
||||
|
||||
parts = new List<VersionToken>();
|
||||
parts = [];
|
||||
for(int i = 0; i < tokens.Length - 1; i++)
|
||||
{
|
||||
var token = tokens[i];
|
||||
|
||||
@@ -8,9 +8,7 @@ using Daybreak.Services.Notifications;
|
||||
using Daybreak.Services.Privilege;
|
||||
using Daybreak.Utils;
|
||||
using Daybreak.Views;
|
||||
using HarfBuzzSharp;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -20,9 +18,7 @@ using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -31,7 +27,7 @@ using static Daybreak.Utils.NativeMethods;
|
||||
|
||||
namespace Daybreak.Services.ApplicationLauncher;
|
||||
|
||||
public class ApplicationLauncher : IApplicationLauncher
|
||||
internal sealed class ApplicationLauncher : IApplicationLauncher
|
||||
{
|
||||
private const int MaxRetries = 10;
|
||||
private const string ProcessName = "gw";
|
||||
@@ -178,9 +174,9 @@ public class ApplicationLauncher : IApplicationLauncher
|
||||
var args = new List<string>()
|
||||
{
|
||||
"-email",
|
||||
email,
|
||||
$"\"{email}\"",
|
||||
"-password",
|
||||
password!.ToString()
|
||||
$"\"{password}\""
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(character))
|
||||
{
|
||||
|
||||
@@ -8,15 +8,15 @@ namespace Daybreak.Services.BuildTemplates;
|
||||
/// Attribute point calculator.
|
||||
/// Based on https://wiki.guildwars.com/wiki/Attribute_point.
|
||||
/// </summary>
|
||||
public sealed class AttributePointCalculator : IAttributePointCalculator
|
||||
internal sealed class AttributePointCalculator : IAttributePointCalculator
|
||||
{
|
||||
private const int MaxRank = 12;
|
||||
private const int MinRank = 0;
|
||||
|
||||
private static readonly List<int> PointsRequiredToIncreaseRankMapping = new()
|
||||
{
|
||||
private static readonly List<int> PointsRequiredToIncreaseRankMapping =
|
||||
[
|
||||
1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, int.MaxValue
|
||||
};
|
||||
];
|
||||
|
||||
public int MaximumAttributePoints => 200;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.BuildTemplates;
|
||||
|
||||
public sealed class BuildTemplateManager : IBuildTemplateManager
|
||||
internal sealed class BuildTemplateManager : IBuildTemplateManager
|
||||
{
|
||||
private const string DecodingLookupTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
private readonly static string BuildsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Guild Wars\\Templates\\Skills";
|
||||
@@ -194,7 +194,7 @@ public sealed class BuildTemplateManager : IBuildTemplateManager
|
||||
var build = new Build()
|
||||
{
|
||||
BuildMetadata = buildMetadata,
|
||||
Skills = new()
|
||||
Skills = []
|
||||
};
|
||||
|
||||
if (Profession.TryParse(buildMetadata.PrimaryProfessionId, out var primaryProfession) is false)
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.Windows.Extensions.Services;
|
||||
|
||||
namespace Daybreak.Services.Charts;
|
||||
|
||||
public sealed class LiveChartInitializer : ILiveChartInitializer, IApplicationLifetimeService
|
||||
internal sealed class LiveChartInitializer : ILiveChartInitializer, IApplicationLifetimeService
|
||||
{
|
||||
public void OnClosing()
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ using System.Text;
|
||||
|
||||
namespace Daybreak.Services.Credentials;
|
||||
|
||||
public sealed class CredentialManager : ICredentialManager
|
||||
internal sealed class CredentialManager : ICredentialManager
|
||||
{
|
||||
private static readonly byte[] Entropy = Convert.FromBase64String("uXB8Vmz5MmuDar36v8SRGzpALi0Wv5Gx");
|
||||
private readonly ILogger<CredentialManager> logger;
|
||||
@@ -44,7 +44,7 @@ public sealed class CredentialManager : ICredentialManager
|
||||
if (config.ProtectedLoginCredentials is null || config.ProtectedLoginCredentials.Count == 0)
|
||||
{
|
||||
this.logger.LogInformation("No credentials found");
|
||||
return new List<LoginCredentials>();
|
||||
return [];
|
||||
}
|
||||
|
||||
return config
|
||||
|
||||
@@ -11,7 +11,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Core.Extensions;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
@@ -23,7 +22,7 @@ namespace Daybreak.Services.DSOAL;
|
||||
/// <summary>
|
||||
/// Service for managing DSOAL for GW1. Credits to: https://lemmy.wtf/post/27911
|
||||
/// </summary>
|
||||
public sealed class DSOALService : IDSOALService
|
||||
internal sealed class DSOALService : IDSOALService
|
||||
{
|
||||
public const string DSOALFixAdminMessage = "Daybreak has detected an issue with the DSOAL installation. In order to fix this issue, Daybreak will need to restart as administrator. DSOAL will not work until then.";
|
||||
public const string DSOALFixRegistryKey = "DSOAL/FixSymbolicLink";
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.Downloads;
|
||||
|
||||
public sealed class DownloadService : IDownloadService
|
||||
internal sealed class DownloadService : IDownloadService
|
||||
{
|
||||
private const double StatusUpdateInterval = 50;
|
||||
private const string MetricUnits = "bytes/sec";
|
||||
|
||||
@@ -11,7 +11,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Daybreak.Services.Drawing;
|
||||
public sealed class DrawingService : IDrawingService, IDrawingModuleProducer
|
||||
internal sealed class DrawingService : IDrawingService, IDrawingModuleProducer
|
||||
{
|
||||
private const int EngagementAreaMultiplier = 9;
|
||||
|
||||
@@ -215,7 +215,7 @@ public sealed class DrawingService : IDrawingService, IDrawingModuleProducer
|
||||
direction.Normalize();
|
||||
var increment = direction * (this.positionRadius + this.positionRadius);
|
||||
|
||||
while (currentPosVector.X != endPosition.X && currentPosVector.Y != endPosition.Y)
|
||||
while (currentPosVector.X != endPosition.X || currentPosVector.Y != endPosition.Y)
|
||||
{
|
||||
var remaining = endVector - currentPosVector;
|
||||
if (remaining.LengthSquared < increment.LengthSquared)
|
||||
|
||||
@@ -14,7 +14,7 @@ public abstract class SvgDrawingModuleBase : DrawingModuleBase
|
||||
{
|
||||
private const int SvgCacheSize = 100;
|
||||
|
||||
private readonly Dictionary<ColorCombination, WriteableBitmap> bitmapCache = new();
|
||||
private readonly Dictionary<ColorCombination, WriteableBitmap> bitmapCache = [];
|
||||
|
||||
protected override bool HasMinimumSize => true;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.Events;
|
||||
|
||||
public sealed class EventNotifierService : IEventNotifierService
|
||||
internal sealed class EventNotifierService : IEventNotifierService
|
||||
{
|
||||
private readonly TimespanToETAConverter timespanToETAConverter = new();
|
||||
private readonly INotificationService notificationService;
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Windows;
|
||||
|
||||
namespace Daybreak.Services.ExceptionHandling;
|
||||
|
||||
public sealed class ExceptionHandler : IExceptionHandler
|
||||
internal sealed class ExceptionHandler : IExceptionHandler
|
||||
{
|
||||
private readonly INotificationService notificationService;
|
||||
private readonly ILogger<ExceptionHandler> logger;
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Extensions.Services;
|
||||
|
||||
namespace Daybreak.Services.ExecutableManagement;
|
||||
public sealed class GuildWarsExecutableManager : IGuildWarsExecutableManager, IApplicationLifetimeService
|
||||
internal sealed class GuildWarsExecutableManager : IGuildWarsExecutableManager, IApplicationLifetimeService
|
||||
{
|
||||
private readonly static TimeSpan ExecutableVerificationLatency = TimeSpan.FromSeconds(5);
|
||||
private readonly static object Lock = new();
|
||||
|
||||
@@ -6,12 +6,12 @@ namespace Daybreak.Services.Experience;
|
||||
/// Based on the explanation from here https://wiki.guildwars.com/wiki/Experience.
|
||||
/// After 182600, the experience threshold is capped.
|
||||
/// </summary>
|
||||
public sealed class ExperienceCalculator : IExperienceCalculator
|
||||
internal sealed class ExperienceCalculator : IExperienceCalculator
|
||||
{
|
||||
private const uint ExperienceCalculationThreshold = 182600;
|
||||
private const uint MaxExperienceRequirement = 15000;
|
||||
private static readonly List<uint> ExperienceThreshold = new()
|
||||
{
|
||||
private static readonly List<uint> ExperienceThreshold =
|
||||
[
|
||||
0,
|
||||
2000,
|
||||
4600,
|
||||
@@ -35,7 +35,7 @@ public sealed class ExperienceCalculator : IExperienceCalculator
|
||||
154000,
|
||||
168000,
|
||||
182600
|
||||
};
|
||||
];
|
||||
|
||||
public uint GetExperienceForCurrentLevel(uint currentTotalExperience)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@ using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@@ -27,7 +26,7 @@ using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Services.Graph;
|
||||
|
||||
public sealed class GraphClient : IGraphClient
|
||||
internal sealed class GraphClient : IGraphClient
|
||||
{
|
||||
private const int MaxBrowserInitializationRetries = 5;
|
||||
|
||||
@@ -44,7 +43,8 @@ public sealed class GraphClient : IGraphClient
|
||||
private const string GraphBaseUrl = "https://graph.microsoft.com/v1.0/";
|
||||
private const string TokenUrlPlaceholder = $"https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
|
||||
private const string AuthorizationUrlPlaceholder = $"https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id={ClientIdPlaceholder}&response_type=code&redirect_uri={RedirectUriPlaceholder}&response_mode=query&scope={ScopesPlaceholder}&state={StatePlaceholder}";
|
||||
private const string SyncFileUri = $"me/drive/root:/Daybreak/Builds/daybreak.json{ContentSuffix}";
|
||||
private const string BuildsSyncFileUri = $"me/drive/root:/Daybreak/Builds/daybreak.json{ContentSuffix}";
|
||||
private const string SettingsSyncFileUri = $"me/drive/root:/Daybreak/Settings/daybreak.json{ContentSuffix}";
|
||||
private const string ContentSuffix = ":/content";
|
||||
|
||||
private static readonly byte[] Entropy = Convert.FromBase64String("R3VpbGR3YXJz");
|
||||
@@ -52,7 +52,7 @@ public sealed class GraphClient : IGraphClient
|
||||
|
||||
private readonly IBuildTemplateManager buildTemplateManager;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly ILiveUpdateableOptions<BuildSynchronizationOptions> liveUpdateableOptions;
|
||||
private readonly ILiveUpdateableOptions<SynchronizationOptions> liveUpdateableOptions;
|
||||
private readonly IHttpClient<GraphClient> httpClient;
|
||||
private readonly ILogger<GraphClient> logger;
|
||||
|
||||
@@ -61,7 +61,7 @@ public sealed class GraphClient : IGraphClient
|
||||
public GraphClient(
|
||||
IBuildTemplateManager buildTemplateManager,
|
||||
IViewManager viewManager,
|
||||
ILiveUpdateableOptions<BuildSynchronizationOptions> liveUpdateableOptions,
|
||||
ILiveUpdateableOptions<SynchronizationOptions> liveUpdateableOptions,
|
||||
IHttpClient<GraphClient> httpClient,
|
||||
ILogger<GraphClient> logger)
|
||||
{
|
||||
@@ -253,6 +253,39 @@ public sealed class GraphClient : IGraphClient
|
||||
this.ResetRefreshToken();
|
||||
}
|
||||
|
||||
public async Task<Result<bool, Exception>> UploadSettings(string settings, CancellationToken cancellationToken)
|
||||
{
|
||||
using var stringContent = new StringContent(settings);
|
||||
try
|
||||
{
|
||||
var response = await this.httpClient.PutAsync(SettingsSyncFileUri, stringContent, cancellationToken);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<string, Exception>> DownloadSettings(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileItemResponse = await this.httpClient.GetAsync(SettingsSyncFileUri, cancellationToken);
|
||||
if (fileItemResponse.IsSuccessStatusCode is false)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var driveItemContent = await fileItemResponse.Content.ReadAsStringAsync(cancellationToken);
|
||||
return driveItemContent;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Optional<TokenResponse>> RefreshAccessToken()
|
||||
{
|
||||
var maybeRefreshToken = this.LoadRefreshToken();
|
||||
@@ -290,7 +323,7 @@ public sealed class GraphClient : IGraphClient
|
||||
SourceUrl = buildEntry.Build?.SourceUrl
|
||||
};
|
||||
|
||||
var buildList = this.buildsCache ?? new List<BuildFile>();
|
||||
var buildList = this.buildsCache ?? [];
|
||||
// Remove the previous version of the build
|
||||
buildList = buildList.Where(b => b.FileName != buildEntry.Name).ToList();
|
||||
// Add new version of the build
|
||||
@@ -299,7 +332,7 @@ public sealed class GraphClient : IGraphClient
|
||||
buildList = buildList.OrderBy(b => b.FileName).ToList();
|
||||
|
||||
using var stringContent = new StringContent(JsonConvert.SerializeObject(buildList));
|
||||
var response = await this.httpClient.PutAsync(SyncFileUri, stringContent);
|
||||
var response = await this.httpClient.PutAsync(BuildsSyncFileUri, stringContent);
|
||||
if (response.IsSuccessStatusCode is false)
|
||||
{
|
||||
return false;
|
||||
@@ -323,7 +356,7 @@ public sealed class GraphClient : IGraphClient
|
||||
buildList = buildList.OrderBy(b => b.FileName).ToList();
|
||||
|
||||
using var stringContent = new StringContent(JsonConvert.SerializeObject(buildList));
|
||||
var response = await this.httpClient.PutAsync(SyncFileUri, stringContent);
|
||||
var response = await this.httpClient.PutAsync(BuildsSyncFileUri, stringContent);
|
||||
if (response.IsSuccessStatusCode is false)
|
||||
{
|
||||
return false;
|
||||
@@ -335,7 +368,7 @@ public sealed class GraphClient : IGraphClient
|
||||
|
||||
private async Task<Optional<List<BuildFile>>> GetBuildsBackup()
|
||||
{
|
||||
var fileItemResponse = await this.httpClient.GetAsync(SyncFileUri);
|
||||
var fileItemResponse = await this.httpClient.GetAsync(BuildsSyncFileUri);
|
||||
if (fileItemResponse.IsSuccessStatusCode is false)
|
||||
{
|
||||
return Optional.None<List<BuildFile>>();
|
||||
|
||||
@@ -19,6 +19,8 @@ public interface IGraphClient
|
||||
Task<Result<bool, Exception>> DownloadBuilds();
|
||||
Task<Result<bool, Exception>> UploadBuild(string buildName);
|
||||
Task<Result<bool, Exception>> DownloadBuild(string buildName);
|
||||
Task<Result<bool, Exception>> UploadSettings(string settings, CancellationToken cancellationToken);
|
||||
Task<Result<string, Exception>> DownloadSettings(CancellationToken cancellationToken);
|
||||
Task<Result<IEnumerable<BuildFile>, Exception>> RetrieveBuildsList();
|
||||
void ResetAuthorization();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Models.Progress;
|
||||
using Daybreak.Models.Progress;
|
||||
using Daybreak.Services.ExecutableManagement;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
@@ -12,7 +10,7 @@ using System.Windows.Forms;
|
||||
|
||||
namespace Daybreak.Services.Guildwars;
|
||||
|
||||
public sealed class GuildwarsCopyService : IGuildwarsCopyService
|
||||
internal sealed class GuildwarsCopyService : IGuildwarsCopyService
|
||||
{
|
||||
private const string ExecutableName = "Gw.exe";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.Guildwars;
|
||||
public sealed class GuildwarsInstaller : IGuildwarsInstaller
|
||||
internal sealed class GuildwarsInstaller : IGuildwarsInstaller
|
||||
{
|
||||
private const string GuildwarsDownloadUri = "https://cloudfront.guildwars2.com/client/GwSetup.exe";
|
||||
private const string InstallationFileName = "GwSetup.exe";
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.IconRetrieve;
|
||||
|
||||
public sealed class IconCache : IIconCache
|
||||
internal sealed class IconCache : IIconCache
|
||||
{
|
||||
private const string HighResolutionGalleryUrl = $"https://wiki.guildwars.com/wiki/File:{NamePlaceholder}_(large).jpg";
|
||||
private const string WikiUrl = "https://wiki.guildwars.com";
|
||||
|
||||
@@ -21,7 +21,7 @@ using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Daybreak.Services.Images;
|
||||
|
||||
public sealed class ImageCache : IImageCache
|
||||
internal sealed class ImageCache : IImageCache
|
||||
{
|
||||
private const string LatencyMetricName = "Image retrieval latency";
|
||||
private const string LatencyMetricDescription = "Number of milliseconds spent while retrieving images";
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.Metrics;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Core.Extensions;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Extensions;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Threading;
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Extensions;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Services.LaunchConfigurations;
|
||||
public sealed class LaunchConfigurationService : ILaunchConfigurationService
|
||||
internal sealed class LaunchConfigurationService : ILaunchConfigurationService
|
||||
{
|
||||
private readonly ICredentialManager credentialManager;
|
||||
private readonly IGuildWarsExecutableManager guildWarsExecutableManager;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging;
|
||||
|
||||
public sealed class CompositeLogsWriter : ILogsWriter
|
||||
internal sealed class CompositeLogsWriter : ILogsWriter
|
||||
{
|
||||
private readonly IEnumerable<ILogsWriter> logsWriters;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging;
|
||||
|
||||
public sealed class DebugLogsWriter : IDebugLogsWriter
|
||||
internal sealed class DebugLogsWriter : IDebugLogsWriter
|
||||
{
|
||||
public void WriteLog(Log log)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging;
|
||||
|
||||
public sealed class EventViewerLogsWriter : IEventViewerLogsWriter
|
||||
internal sealed class EventViewerLogsWriter : IEventViewerLogsWriter
|
||||
{
|
||||
private const string AppName = "Daybreak";
|
||||
private const string LogType = "Application";
|
||||
|
||||
@@ -11,11 +11,11 @@ using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging;
|
||||
|
||||
public sealed class JsonLogsManager : ILogsManager
|
||||
internal sealed class JsonLogsManager : ILogsManager
|
||||
{
|
||||
private const int MemoryCacheMaxSize = 5000;
|
||||
|
||||
private readonly List<Models.Log> memoryCache = new();
|
||||
private readonly List<Models.Log> memoryCache = [];
|
||||
private readonly ILiteCollection<Models.Log> collection;
|
||||
private readonly ILiveOptions<LauncherOptions> liveOptions;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Core.Extensions;
|
||||
|
||||
namespace Daybreak.Services.Menu;
|
||||
|
||||
public sealed class MenuService : IMenuService, IMenuServiceInitializer
|
||||
internal sealed class MenuService : IMenuService, IMenuServiceInitializer
|
||||
{
|
||||
private readonly ILogger<MenuService> logger;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.Threading;
|
||||
|
||||
namespace Daybreak.Services.Metrics;
|
||||
|
||||
public sealed class MetricsService : IMetricsService, IDisposable
|
||||
internal sealed class MetricsService : IMetricsService, IDisposable
|
||||
{
|
||||
private const int MetricsStoreLimit = 10000;
|
||||
private const string MetricsNamespace = "Daybreak";
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Core.Extensions;
|
||||
|
||||
namespace Daybreak.Services.Mods;
|
||||
|
||||
public sealed class ModsManager : IModsManager
|
||||
internal sealed class ModsManager : IModsManager
|
||||
{
|
||||
private readonly IServiceManager serviceManager;
|
||||
private readonly ILogger<IModsManager> logger;
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Threading;
|
||||
|
||||
namespace Daybreak.Services.Monitoring;
|
||||
|
||||
public sealed class DiskUsageMonitor : IApplicationLifetimeService
|
||||
internal sealed class DiskUsageMonitor : IApplicationLifetimeService
|
||||
{
|
||||
private const string WriteDiskUsage = "Write Disk Usage";
|
||||
private const string WriteDiskUsageUnit = "MBs/s";
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Threading;
|
||||
|
||||
namespace Daybreak.Services.Monitoring;
|
||||
|
||||
public sealed class MemoryUsageMonitor : IApplicationLifetimeService
|
||||
internal sealed class MemoryUsageMonitor : IApplicationLifetimeService
|
||||
{
|
||||
private const string MemoryUsage = "Memory Usage";
|
||||
private const string MemoryUsageUnit = "MBs";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user