mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-19 23:05:03 +00:00
Compare commits
49
Commits
v0.9.8.128
...
v0.9.9.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c53456112a | ||
|
|
ccea21886e | ||
|
|
37be8de5ac | ||
|
|
107e43a15f | ||
|
|
17b3ed34db | ||
|
|
cce9cd34af | ||
|
|
6a80f8ee5d | ||
|
|
edb7f0d0bd | ||
|
|
8e69375338 | ||
|
|
d24ae98fb0 | ||
|
|
111b3ea632 | ||
|
|
cc1e759972 | ||
|
|
ad0527ed73 | ||
|
|
8ffbb918ea | ||
|
|
c27a0dba65 | ||
|
|
ad8305c66d | ||
|
|
29fe12f094 | ||
|
|
9dbe4c5eaf | ||
|
|
1e9aca3807 | ||
|
|
895da23f7d | ||
|
|
f788a10879 | ||
|
|
9fe4be0467 | ||
|
|
b1a7d3a111 | ||
|
|
8b9fdaaa30 | ||
|
|
60d5947535 | ||
|
|
0ba0e64a2a | ||
|
|
e1dfd1f0d0 | ||
|
|
cd2a529381 | ||
|
|
6ba8dcac49 | ||
|
|
f2e76b5459 | ||
|
|
cfbf6ed021 | ||
|
|
a372eb5125 | ||
|
|
76b89ca0e8 | ||
|
|
2c1721d52c | ||
|
|
324a77a625 | ||
|
|
88e59b8ec9 | ||
|
|
df71a17d9f | ||
|
|
8451f53e19 | ||
|
|
e795af5c11 | ||
|
|
efa3c5175c | ||
|
|
32efe42a61 | ||
|
|
97d2d09cdc | ||
|
|
ed90d567a4 | ||
|
|
51d6fb0f42 | ||
|
|
c10525708c | ||
|
|
0a69d795aa | ||
|
|
3b1d6831a5 | ||
|
|
b4c1dbcddb | ||
|
|
db5d62d7c0 |
@@ -50,9 +50,9 @@ jobs:
|
||||
LatestReleaseTag: ${{steps.getLatestTag.outputs.tag}}
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '7.x'
|
||||
dotnet-version: '8.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1
|
||||
@@ -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 --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 }}
|
||||
|
||||
@@ -92,13 +92,24 @@ jobs:
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish extractor files
|
||||
run: dotnet publish .\Daybreak.7ZipExtractor\Daybreak.7ZipExtractor.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=false --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Pack publish files
|
||||
run: |
|
||||
Write-Host $env
|
||||
.\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
|
||||
@@ -108,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,9 +36,9 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '7.x'
|
||||
dotnet-version: '8.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1
|
||||
|
||||
@@ -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,9 +70,9 @@ 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: '7.x'
|
||||
dotnet-version: '8.x'
|
||||
|
||||
#- name: Autobuild
|
||||
# uses: github/codeql-action/autobuild@v2
|
||||
@@ -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
|
||||
|
||||
@@ -28,7 +28,12 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.x'
|
||||
|
||||
- name: Get Latest Tag
|
||||
id: getLatestTag
|
||||
uses: WyriHaximus/github-action-get-previous-tag@v1
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "GWCA"]
|
||||
path = GWCA
|
||||
url = https://github.com/GregLando113/GWCA
|
||||
url = https://github.com/gwdevhub/GWCA
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>Daybreak._7ZipExtractor</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpCompress" Version="0.36.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Extractor is in a different executable because of memory limitations. Daybreak needs to be compiled for x86 and as such has a memory limit of 2GB.
|
||||
* 7Zip algorithm may require more than 2GB memory to unpack large zip files.
|
||||
* As such, Daybreak.7ZipExtractor is x64.
|
||||
*/
|
||||
using SharpCompress.Archives;
|
||||
|
||||
if (args.Length != 2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var archivePath = args[0];
|
||||
var destinationDirectory = args[1];
|
||||
|
||||
using var fileStream = new FileStream(archivePath, FileMode.Open);
|
||||
using var archive = ArchiveFactory.Open(fileStream);
|
||||
var progress = 0d;
|
||||
var count = archive.Entries.Count();
|
||||
var reader = archive.ExtractAllEntries();
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
var entry = reader.Entry;
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
var directoryName = Path.Combine(Path.GetFullPath(destinationDirectory), entry.Key);
|
||||
Directory.CreateDirectory(directoryName);
|
||||
continue;
|
||||
}
|
||||
|
||||
var fileName = Path.Combine(Path.GetFullPath(destinationDirectory), entry.Key);
|
||||
using var entryStream = new FileStream(fileName, FileMode.Create);
|
||||
using (var stream = reader.OpenEntryStream())
|
||||
{
|
||||
stream.CopyTo(entryStream);
|
||||
}
|
||||
|
||||
progress += 1d / count;
|
||||
Console.WriteLine($"{progress} {fileName}");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2,17 +2,28 @@
|
||||
# project specific logic here.
|
||||
#
|
||||
|
||||
project(Daybreak.GWCA)
|
||||
project(Daybreak.GWCA VERSION 1.0.0)
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message(FATAL_ERROR "You are configuring a 64bit build, this is not supported. Run cmake with `-A Win32`")
|
||||
endif()
|
||||
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 9)
|
||||
set(VERSION_PATCH 9)
|
||||
set(VERSION_TWEAK 6)
|
||||
|
||||
set(VERSION_RC "${CMAKE_CURRENT_BINARY_DIR}/version.rc")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in" "${VERSION_RC}" @ONLY)
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin")
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(Daybreak.GWCA_FOLDER "${CMAKE_CURRENT_LIST_DIR}/")
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/bin/install)
|
||||
add_compile_options(/MP /permissive-)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/")
|
||||
|
||||
add_library(Daybreak.GWCA SHARED)
|
||||
@@ -23,11 +34,13 @@ file(GLOB SOURCES
|
||||
"header/*.h*"
|
||||
"header/*/*.h")
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES})
|
||||
target_sources(Daybreak.GWCA PRIVATE ${SOURCES})
|
||||
source_group("Generated Files" FILES ${VERSION_RC})
|
||||
target_sources(Daybreak.GWCA PRIVATE ${SOURCES} ${VERSION_RC})
|
||||
target_compile_features(Daybreak.GWCA PUBLIC cxx_std_17)
|
||||
target_compile_definitions(Daybreak.GWCA PRIVATE
|
||||
$<$<CONFIG:Debug>:BUILD_TYPE_DEBUG>
|
||||
$<$<CONFIG:Release>:BUILD_TYPE_RELEASE>
|
||||
NOMINMAX
|
||||
)
|
||||
|
||||
target_precompile_headers(Daybreak.GWCA PRIVATE "header/pch.h")
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "httplib.h"
|
||||
|
||||
namespace Daybreak::Modules::EntityNameModule {
|
||||
void GetName(const httplib::Request& req, httplib::Response& res);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "httplib.h"
|
||||
|
||||
namespace Daybreak::Modules::GameStateModule {
|
||||
void GetGameStateInfo(const httplib::Request&, httplib::Response& res);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "httplib.h"
|
||||
|
||||
namespace Daybreak::Modules::NameModule {
|
||||
namespace Daybreak::Modules::ItemNameModule {
|
||||
void GetName(const httplib::Request& req, httplib::Response& res);
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
namespace http {
|
||||
namespace server {
|
||||
bool StartServer();
|
||||
void StopServer();
|
||||
void SetLogger(httplib::Logger logger);
|
||||
void Get(const std::string& pattern, httplib::Server::Handler handler);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace Daybreak::Utils {
|
||||
std::string WStringToString(const std::wstring& wstr);
|
||||
bool StringToInt(const std::string& str, int& outValue);
|
||||
}
|
||||
+8220
-8254
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <json.hpp>
|
||||
#include <payloads/StatePayload.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Daybreak {
|
||||
struct GameStatePayload {
|
||||
std::list<StatePayload> States;
|
||||
};
|
||||
|
||||
void to_json(json& j, const GameStatePayload& p);
|
||||
}
|
||||
@@ -17,6 +17,8 @@ namespace Daybreak {
|
||||
uint32_t Level = 0;
|
||||
uint32_t EntityState = 0;
|
||||
uint32_t EntityAllegiance = 0;
|
||||
float Health;
|
||||
float Energy;
|
||||
};
|
||||
|
||||
void to_json(json& j, const LivingEntity& p);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Daybreak {
|
||||
struct StatePayload {
|
||||
uint32_t Id = 0;
|
||||
float PosX = 0;
|
||||
float PosY = 0;
|
||||
uint32_t State = 0;
|
||||
float Health = 0;
|
||||
float Energy = 0;
|
||||
};
|
||||
|
||||
void to_json(json& j, const StatePayload& p);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "pch.h"
|
||||
#include "NameModule.h"
|
||||
#include "EntityNameModule.h"
|
||||
#include "payloads/NamePayload.h"
|
||||
#include <GWCA/Managers/GameThreadMgr.h>
|
||||
#include <GWCA/Managers/MapMgr.h>
|
||||
@@ -14,46 +14,34 @@
|
||||
#include <Windows.h>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include "Utils.h"
|
||||
|
||||
namespace Daybreak::Modules::NameModule {
|
||||
namespace Daybreak::Modules::EntityNameModule {
|
||||
std::vector<std::tuple<uint32_t, std::promise<NamePayload>*, std::wstring*>> WaitingList;
|
||||
std::queue<std::tuple<uint32_t, std::promise<NamePayload>>*> PromiseQueue;
|
||||
std::mutex GameThreadMutex;
|
||||
GW::HookEntry GameThreadHook;
|
||||
volatile bool initialized = false;
|
||||
|
||||
std::string WStringToString(const std::wstring& wstr)
|
||||
{
|
||||
if (wstr.empty()) return std::string();
|
||||
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
|
||||
std::string strTo(size_needed, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
|
||||
|
||||
return strTo;
|
||||
}
|
||||
|
||||
NamePayload GetAsyncName(uint32_t id) {
|
||||
std::wstring* GetAsyncName(uint32_t id) {
|
||||
NamePayload namePayload;
|
||||
auto name = new std::wstring();
|
||||
auto agent = GW::Agents::GetAgentByID(id);
|
||||
if (!agent) {
|
||||
return namePayload;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto agentLiving = agent->GetAsAgentLiving();
|
||||
if (!agentLiving) {
|
||||
return namePayload;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto name = new std::wstring();
|
||||
if (!GW::Agents::AsyncGetAgentName(agentLiving, *name)) {
|
||||
return namePayload;
|
||||
delete(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto namestr = WStringToString(*name);
|
||||
namePayload.Id = id;
|
||||
namePayload.Name = namestr;
|
||||
delete(name);
|
||||
return namePayload;
|
||||
return name;
|
||||
}
|
||||
|
||||
void EnsureInitialized() {
|
||||
@@ -62,18 +50,40 @@ namespace Daybreak::Modules::NameModule {
|
||||
GW::GameThread::RegisterGameThreadCallback(&GameThreadHook, [&](GW::HookStatus*) {
|
||||
while (!PromiseQueue.empty()) {
|
||||
auto promiseRequest = PromiseQueue.front();
|
||||
std::promise<NamePayload>& promise = std::get<1>(*promiseRequest);
|
||||
std::promise<NamePayload> &promise = std::get<1>(*promiseRequest);
|
||||
uint32_t id = std::get<0>(*promiseRequest);
|
||||
PromiseQueue.pop();
|
||||
try {
|
||||
auto payload = GetAsyncName(id);
|
||||
promise.set_value(payload);
|
||||
auto name = GetAsyncName(id);
|
||||
if (!name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WaitingList.emplace_back(id, &promise, name);
|
||||
}
|
||||
catch (...) {
|
||||
NamePayload payload;
|
||||
promise.set_value(payload);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = 0; i < WaitingList.size(); ) {
|
||||
auto item = &WaitingList[i];
|
||||
auto name = std::get<2>(*item);
|
||||
if (name->empty()) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto promise = std::get<1>(*item);
|
||||
auto id = std::get<0>(*item);
|
||||
WaitingList.erase(WaitingList.begin() + i);
|
||||
NamePayload payload;
|
||||
payload.Id = id;
|
||||
payload.Name = Daybreak::Utils::WStringToString(*name);
|
||||
delete(name);
|
||||
promise->set_value(payload);
|
||||
}
|
||||
});
|
||||
|
||||
initialized = true;
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <json.hpp>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include "Utils.h"
|
||||
|
||||
namespace Daybreak::Modules::GameModule {
|
||||
std::queue<std::promise<GamePayload>*> PromiseQueue;
|
||||
@@ -31,17 +32,6 @@ namespace Daybreak::Modules::GameModule {
|
||||
GW::HookEntry GameThreadHook;
|
||||
volatile bool initialized = false;
|
||||
|
||||
std::string GetString(wchar_t* chars) {
|
||||
if (!chars) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string str(64, '\0');
|
||||
auto length = std::wcstombs(&str[0], chars, 64);
|
||||
str.resize(length);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::list<QuestMetadata> GetQuestLog() {
|
||||
std::list<QuestMetadata> questMetadatas;
|
||||
auto questLog = GW::QuestMgr::GetQuestLog();
|
||||
@@ -54,8 +44,8 @@ namespace Daybreak::Modules::GameModule {
|
||||
metadata.FromId = (uint32_t)quest.map_from;
|
||||
metadata.ToId = (uint32_t)quest.map_to;
|
||||
metadata.Id = (uint32_t)quest.quest_id;
|
||||
metadata.PosX = (uint32_t)quest.marker.x;
|
||||
metadata.PosY = (uint32_t)quest.marker.y;
|
||||
metadata.PosX = quest.marker.x;
|
||||
metadata.PosY = quest.marker.y;
|
||||
questMetadatas.push_back(metadata);
|
||||
}
|
||||
|
||||
@@ -110,16 +100,6 @@ namespace Daybreak::Modules::GameModule {
|
||||
return agentList;
|
||||
}
|
||||
|
||||
std::list<GW::NPC> GetNpcs() {
|
||||
std::list<GW::NPC> npcs;
|
||||
auto worldContext = GW::GetWorldContext();
|
||||
for (auto& npc : worldContext->npcs) {
|
||||
npcs.push_back(npc);
|
||||
}
|
||||
|
||||
return npcs;
|
||||
}
|
||||
|
||||
std::vector<GW::TitleTier> GetTitleTiers() {
|
||||
std::vector<GW::TitleTier> titles;
|
||||
auto worldContext = GW::GetWorldContext();
|
||||
@@ -196,6 +176,16 @@ namespace Daybreak::Modules::GameModule {
|
||||
entity.Level = agent.level;
|
||||
entity.PosX = agent.pos.x;
|
||||
entity.PosY = agent.pos.y;
|
||||
entity.Health = agent.hp;
|
||||
entity.Energy = agent.energy;
|
||||
if (agent.primary == 0) {
|
||||
const auto npc = GW::Agents::GetNPCByID(agent.player_number);
|
||||
if (npc) {
|
||||
entity.PrimaryProfessionId = npc->primary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
entities.push_back(entity);
|
||||
}
|
||||
|
||||
@@ -265,6 +255,8 @@ namespace Daybreak::Modules::GameModule {
|
||||
player.NpcDefinition = agent->player_number;
|
||||
player.PrimaryProfessionId = (uint32_t)agent->primary;
|
||||
player.SecondaryProfessionId = (uint32_t)agent->secondary;
|
||||
player.Health = agent->hp * (agent->max_hp > 0 ? agent->max_hp : 1);
|
||||
player.Energy = agent->energy * (agent->max_energy > 0 ? agent->max_energy : 1);
|
||||
}
|
||||
else if (professionState) {
|
||||
player.PrimaryProfessionId = (uint32_t)professionState->primary;
|
||||
@@ -291,9 +283,15 @@ namespace Daybreak::Modules::GameModule {
|
||||
GW::Title gwTitle;
|
||||
Title title;
|
||||
int titleId = 0;
|
||||
auto name = GetString(gwPlayer->name);
|
||||
std::wstring nameString(gwPlayer->name);
|
||||
auto name = Daybreak::Utils::WStringToString(nameString);
|
||||
player.Name = name;
|
||||
|
||||
if (titles.empty() ||
|
||||
titleTiers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &t : titles) {
|
||||
if (t.current_title_tier_index == gwPlayer->active_title_tier) {
|
||||
gwTitle = t;
|
||||
@@ -367,25 +365,14 @@ namespace Daybreak::Modules::GameModule {
|
||||
}
|
||||
|
||||
auto titles = GetTitles();
|
||||
if (titles.empty()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto titleTiers = GetTitleTiers();
|
||||
if (titleTiers.empty()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto players = GetPlayers();
|
||||
if (players.empty()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto npcs = GetNpcs();
|
||||
if (npcs.empty()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto attributes = GetPartyAttributes();
|
||||
if (attributes.empty()) {
|
||||
return gamePayload;
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "pch.h"
|
||||
#include "GameStateModule.h"
|
||||
#include <GWCA/Managers/GameThreadMgr.h>
|
||||
#include <GWCA/Managers/AgentMgr.h>
|
||||
#include <GWCA/GameEntities/Agent.h>
|
||||
#include <GWCA/Managers/MapMgr.h>
|
||||
#include <future>
|
||||
#include <payloads/GameStatePayload.h>
|
||||
#include <json.hpp>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Daybreak::Modules::GameStateModule {
|
||||
std::queue<std::promise<GameStatePayload>*> PromiseQueue;
|
||||
std::mutex GameThreadMutex;
|
||||
GW::HookEntry GameThreadHook;
|
||||
volatile bool initialized = false;
|
||||
|
||||
std::list<GW::AgentLiving> GetLivingAgents() {
|
||||
std::list<GW::AgentLiving> agentList;
|
||||
const GW::AgentArray* agents_ptr = GW::Agents::GetAgentArray();
|
||||
GW::AgentArray* agents = GW::Agents::GetAgentArray();
|
||||
if (!agents) {
|
||||
return agentList;
|
||||
}
|
||||
|
||||
for (auto* a : *agents) {
|
||||
const GW::AgentLiving* agent = a ? a->GetAsAgentLiving() : nullptr;
|
||||
if (agent) {
|
||||
agentList.push_back(*agent);
|
||||
}
|
||||
}
|
||||
|
||||
return agentList;
|
||||
}
|
||||
|
||||
std::list<StatePayload> GetStates(
|
||||
std::list<GW::AgentLiving> agents) {
|
||||
std::list<StatePayload> states;
|
||||
for (auto& agent : agents) {
|
||||
StatePayload state;
|
||||
state.Id = agent.agent_id;
|
||||
state.PosX = agent.pos.x;
|
||||
state.PosY = agent.pos.y;
|
||||
state.State = agent.type_map;
|
||||
state.Health = agent.hp * (agent.max_hp > 0 ? agent.max_hp : 1);
|
||||
state.Energy = agent.energy * (agent.max_energy > 0 ? agent.max_energy : 1);
|
||||
states.push_back(state);
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
GameStatePayload GetPayload() {
|
||||
GameStatePayload gamePayload;
|
||||
if (!GW::Map::GetIsMapLoaded()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto agents = GetLivingAgents();
|
||||
if (agents.empty()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto states = GetStates(agents);
|
||||
gamePayload.States = states;
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
void EnsureInitialized() {
|
||||
GameThreadMutex.lock();
|
||||
if (!initialized) {
|
||||
GW::GameThread::RegisterGameThreadCallback(&GameThreadHook, [&](GW::HookStatus*) {
|
||||
while (!PromiseQueue.empty()) {
|
||||
auto promise = PromiseQueue.front();
|
||||
PromiseQueue.pop();
|
||||
try {
|
||||
auto payload = GetPayload();
|
||||
promise->set_value(payload);
|
||||
}
|
||||
catch (...) {
|
||||
GameStatePayload payload;
|
||||
promise->set_value(payload);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
GameThreadMutex.unlock();
|
||||
}
|
||||
|
||||
void GetGameStateInfo(const httplib::Request&, httplib::Response& res) {
|
||||
auto callbackEntry = new GW::HookEntry;
|
||||
auto response = new std::promise<GameStatePayload>;
|
||||
|
||||
EnsureInitialized();
|
||||
PromiseQueue.emplace(response);
|
||||
json responsePayload = response->get_future().get();
|
||||
|
||||
delete callbackEntry;
|
||||
delete response;
|
||||
res.set_content(responsePayload.dump(), "text/json");
|
||||
}
|
||||
}
|
||||
@@ -28,12 +28,12 @@ namespace Daybreak::Modules::InventoryModule {
|
||||
continue;
|
||||
}
|
||||
|
||||
bagContent.Id = item->item_id;
|
||||
bagContent.Id = item->model_id;
|
||||
bagContent.Slot = item->slot;
|
||||
bagContent.Count = item->quantity;
|
||||
auto modifier = item->mod_struct;
|
||||
for (auto i = 0; i < item->mod_struct_size; i++) {
|
||||
bagContent.Modifiers.push_back((uint32_t)modifier);
|
||||
bagContent.Modifiers.push_back((uint32_t)(modifier->mod));
|
||||
modifier++;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "pch.h"
|
||||
#include "ItemNameModule.h"
|
||||
#include "payloads/NamePayload.h"
|
||||
#include <GWCA/Managers/GameThreadMgr.h>
|
||||
#include <GWCA/Managers/ItemMgr.h>
|
||||
#include <GWCA/GameEntities/Item.h>
|
||||
#include <future>
|
||||
#include <json.hpp>
|
||||
#include <tuple>
|
||||
#include <queue>
|
||||
#include <GWCA/GWCA.h>
|
||||
#include <Windows.h>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <Utils.h>
|
||||
|
||||
namespace Daybreak::Modules::ItemNameModule {
|
||||
std::vector<std::tuple<uint32_t, std::promise<NamePayload>*, std::wstring*>> WaitingList;
|
||||
std::queue<std::tuple<uint32_t, std::vector<uint32_t>, std::promise<NamePayload>>*> PromiseQueue;
|
||||
std::mutex GameThreadMutex;
|
||||
GW::HookEntry GameThreadHook;
|
||||
volatile bool initialized = false;
|
||||
|
||||
std::wstring* GetAsyncName(uint32_t id, std::vector<uint32_t> modifiers) {
|
||||
GW::ItemModifier parsedModifiers[64];
|
||||
for (auto i = 0; i < modifiers.size(); i++) {
|
||||
GW::ItemModifier parsedModifier;
|
||||
const auto mod = modifiers.at(i);
|
||||
parsedModifier.mod = mod;
|
||||
parsedModifiers[i] = parsedModifier;
|
||||
}
|
||||
|
||||
auto item = GW::Items::GetItemByModelIdAndModifiers(id, parsedModifiers, modifiers.size(), 1, 23);
|
||||
if (!item) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto name = new std::wstring();
|
||||
GW::Items::AsyncGetItemName(item, *name);
|
||||
return name;
|
||||
}
|
||||
|
||||
void EnsureInitialized() {
|
||||
GameThreadMutex.lock();
|
||||
if (!initialized) {
|
||||
GW::GameThread::RegisterGameThreadCallback(&GameThreadHook, [&](GW::HookStatus*) {
|
||||
while (!PromiseQueue.empty()) {
|
||||
auto promiseRequest = PromiseQueue.front();
|
||||
std::promise<NamePayload> &promise = std::get<2>(*promiseRequest);
|
||||
uint32_t id = std::get<0>(*promiseRequest);
|
||||
auto modifiers = std::get<1>(*promiseRequest);
|
||||
PromiseQueue.pop();
|
||||
try {
|
||||
auto name = GetAsyncName(id, modifiers);
|
||||
if (!name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WaitingList.emplace_back(id, &promise, name);
|
||||
}
|
||||
catch (...) {
|
||||
NamePayload payload;
|
||||
promise.set_value(payload);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < WaitingList.size(); ) {
|
||||
auto item = &WaitingList[i];
|
||||
auto name = std::get<2>(*item);
|
||||
if (name->empty()) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto promise = std::get<1>(*item);
|
||||
auto id = std::get<0>(*item);
|
||||
WaitingList.erase(WaitingList.begin() + i);
|
||||
NamePayload payload;
|
||||
payload.Id = id;
|
||||
payload.Name = Daybreak::Utils::WStringToString(*name);
|
||||
delete(name);
|
||||
promise->set_value(payload);
|
||||
}
|
||||
});
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
GameThreadMutex.unlock();
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitAndRemoveSpaces(const std::string& s) {
|
||||
std::vector<std::string> result;
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
|
||||
while (getline(ss, item, ',')) {
|
||||
item.erase(std::remove(item.begin(), item.end(), ' '), item.end());
|
||||
result.push_back(item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GetName(const httplib::Request& req, httplib::Response& res) {
|
||||
auto callbackEntry = new GW::HookEntry;
|
||||
uint32_t id = 0;
|
||||
std::vector<uint32_t> modifiers;
|
||||
|
||||
auto id_it = req.params.find("id");
|
||||
if (id_it == req.params.end()) {
|
||||
res.status = 400;
|
||||
res.set_content("Missing id parameter", "text/plain");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
auto& idStr = id_it->second;
|
||||
int parsedId;
|
||||
if (!Daybreak::Utils::StringToInt(idStr, parsedId)){
|
||||
res.status = 400;
|
||||
res.set_content("Invalid id parameter", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
id = static_cast<uint32_t>(parsedId);
|
||||
}
|
||||
|
||||
auto mod_it = req.params.find("modifiers");
|
||||
if (mod_it == req.params.end()) {
|
||||
res.status = 400;
|
||||
res.set_content("Missing modifiers parameter", "text/plain");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
auto& modifiersStr = mod_it->second;
|
||||
const auto tokens = SplitAndRemoveSpaces(modifiersStr);
|
||||
for (const auto& token : tokens) {
|
||||
int parsedModifier;
|
||||
if (!Daybreak::Utils::StringToInt(token, parsedModifier)) {
|
||||
res.status = 400;
|
||||
res.set_content("Invalid modifier parameter", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
modifiers.push_back(static_cast<uint32_t>(parsedModifier));
|
||||
}
|
||||
}
|
||||
|
||||
auto response = new std::tuple<uint32_t, std::vector<uint32_t>, std::promise<NamePayload>>();
|
||||
std::get<0>(*response) = id;
|
||||
std::promise<NamePayload>& promise = std::get<2>(*response);
|
||||
std::get<1>(*response) = modifiers;
|
||||
|
||||
EnsureInitialized();
|
||||
PromiseQueue.emplace(response);
|
||||
|
||||
json responsePayload = promise.get_future().get();
|
||||
delete callbackEntry;
|
||||
delete response;
|
||||
res.set_content(responsePayload.dump(), "text/json");
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <payloads/LoginPayload.h>
|
||||
#include <json.hpp>
|
||||
#include <queue>
|
||||
#include "Utils.h"
|
||||
|
||||
namespace Daybreak::Modules::LoginModule {
|
||||
std::queue<std::promise<LoginPayload>*> PromiseQueue;
|
||||
@@ -17,15 +18,10 @@ namespace Daybreak::Modules::LoginModule {
|
||||
LoginPayload GetPayload() {
|
||||
auto context = GW::GetCharContext();
|
||||
LoginPayload loginPayload;
|
||||
std::string emailstr(64, '\0');
|
||||
auto length = std::wcstombs(&emailstr[0], context->player_email, 64);
|
||||
emailstr.resize(length);
|
||||
loginPayload.Email = emailstr;
|
||||
|
||||
std::string playerstr(20, '\0');
|
||||
length = std::wcstombs(&playerstr[0], context->player_name, 20);
|
||||
playerstr.resize(length);
|
||||
loginPayload.PlayerName = playerstr;
|
||||
std::wstring playerEmail(context->player_email);
|
||||
std::wstring playerName(context->player_name);
|
||||
loginPayload.Email = Daybreak::Utils::WStringToString(playerEmail);
|
||||
loginPayload.PlayerName = Daybreak::Utils::WStringToString(playerName);
|
||||
|
||||
return loginPayload;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <json.hpp>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include "Utils.h"
|
||||
|
||||
namespace Daybreak::Modules::MainPlayerModule {
|
||||
std::queue<std::promise<MainPlayer>*> PromiseQueue;
|
||||
@@ -31,17 +32,6 @@ namespace Daybreak::Modules::MainPlayerModule {
|
||||
GW::HookEntry GameThreadHook;
|
||||
volatile bool initialized = false;
|
||||
|
||||
std::string GetString(wchar_t* chars) {
|
||||
if (!chars) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string str(64, '\0');
|
||||
auto length = std::wcstombs(&str[0], chars, 64);
|
||||
str.resize(length);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::list<QuestMetadata> GetQuestLog() {
|
||||
std::list<QuestMetadata> questMetadatas;
|
||||
auto questLog = GW::QuestMgr::GetQuestLog();
|
||||
@@ -54,8 +44,8 @@ namespace Daybreak::Modules::MainPlayerModule {
|
||||
metadata.FromId = (uint32_t)quest.map_from;
|
||||
metadata.ToId = (uint32_t)quest.map_to;
|
||||
metadata.Id = (uint32_t)quest.quest_id;
|
||||
metadata.PosX = (uint32_t)quest.marker.x;
|
||||
metadata.PosY = (uint32_t)quest.marker.y;
|
||||
metadata.PosX = quest.marker.x;
|
||||
metadata.PosY = quest.marker.y;
|
||||
questMetadatas.push_back(metadata);
|
||||
}
|
||||
|
||||
@@ -265,6 +255,8 @@ namespace Daybreak::Modules::MainPlayerModule {
|
||||
player.NpcDefinition = agent->player_number;
|
||||
player.PrimaryProfessionId = (uint32_t)agent->primary;
|
||||
player.SecondaryProfessionId = (uint32_t)agent->secondary;
|
||||
player.Health = agent->hp * (agent->max_hp > 0 ? agent->max_hp : 1);
|
||||
player.Energy = agent->energy * (agent->max_energy > 0 ? agent->max_energy : 1);
|
||||
}
|
||||
else if (professionState) {
|
||||
player.PrimaryProfessionId = (uint32_t)professionState->primary;
|
||||
@@ -291,9 +283,15 @@ namespace Daybreak::Modules::MainPlayerModule {
|
||||
GW::Title gwTitle;
|
||||
Title title;
|
||||
int titleId = 0;
|
||||
auto name = GetString(gwPlayer->name);
|
||||
std::wstring gwPlayerName(gwPlayer->name);
|
||||
auto name = Daybreak::Utils::WStringToString(gwPlayerName);
|
||||
player.Name = name;
|
||||
|
||||
if (titles.empty() ||
|
||||
titleTiers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &t : titles) {
|
||||
if (t.current_title_tier_index == gwPlayer->active_title_tier) {
|
||||
gwTitle = t;
|
||||
@@ -365,14 +363,8 @@ namespace Daybreak::Modules::MainPlayerModule {
|
||||
}
|
||||
|
||||
auto titles = GetTitles();
|
||||
if (titles.empty()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto titleTiers = GetTitleTiers();
|
||||
if (titleTiers.empty()) {
|
||||
return gamePayload;
|
||||
}
|
||||
|
||||
auto players = GetPlayers();
|
||||
if (players.empty()) {
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Daybreak::Modules::MapModule {
|
||||
auto region = GW::Map::GetRegion();
|
||||
auto mapId = GW::Map::GetMapID();
|
||||
MapPayload mapPayload;
|
||||
mapPayload.Campaign = mapInfo->campaign;
|
||||
mapPayload.Continent = mapInfo->continent;
|
||||
mapPayload.Campaign = static_cast<uint32_t>(mapInfo->campaign);
|
||||
mapPayload.Continent = static_cast<uint32_t>(mapInfo->continent);
|
||||
mapPayload.Region = mapInfo->region;
|
||||
mapPayload.InstanceType = (uint32_t)instanceType;
|
||||
mapPayload.IsLoaded = isLoaded;
|
||||
|
||||
@@ -62,11 +62,18 @@ namespace http {
|
||||
int port = FindPort();
|
||||
if (port > 0) {
|
||||
std::cout << "Initializing server on port " << port << std::endl;
|
||||
server.set_read_timeout(1, 0);
|
||||
server.set_write_timeout(1, 0);
|
||||
server.set_idle_interval(0, 100000);
|
||||
server.listen("0.0.0.0", port);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StopServer() {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "pch.h"
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Daybreak::Utils {
|
||||
std::string WStringToString(const std::wstring& wstr)
|
||||
{
|
||||
if (wstr.empty()) return std::string();
|
||||
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
|
||||
std::string strTo(size_needed, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
|
||||
|
||||
return strTo;
|
||||
}
|
||||
|
||||
bool StringToInt(const std::string& str, int& outValue) {
|
||||
size_t pos = 0;
|
||||
unsigned long result = std::stoul(str, &pos);
|
||||
|
||||
// Ensure the entire string was processed
|
||||
if (pos != str.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outValue = static_cast<int>(result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,11 @@
|
||||
#include "pch.h"
|
||||
#include "httplib.h"
|
||||
#include <GWCA/GWCA.h>
|
||||
#include <GWCA/Utilities/Scanner.h>
|
||||
#include <GWCA/Utilities/Hook.h>
|
||||
#include <GWCA/Utilities/Hooker.h>
|
||||
#include <GWCA/Managers/RenderMgr.h>
|
||||
#include <GWCA/Managers/MemoryMgr.h>
|
||||
#include "AliveModule.h"
|
||||
#include "ProcessIdModule.h"
|
||||
#include "HttpLogger.h"
|
||||
@@ -16,26 +21,41 @@
|
||||
#include "GameModule.h"
|
||||
#include "MainPlayerModule.h"
|
||||
#include "SessionModule.h"
|
||||
#include "NameModule.h"
|
||||
#include "EntityNameModule.h"
|
||||
#include "GameStateModule.h"
|
||||
#include "ItemNameModule.h"
|
||||
#include <mutex>
|
||||
|
||||
volatile bool initialized;
|
||||
volatile WNDPROC oldWndProc;
|
||||
std::mutex startupMutex;
|
||||
HMODULE dllmodule;
|
||||
HANDLE serverThread;
|
||||
static FILE* stdout_proxy;
|
||||
static FILE* stderr_proxy;
|
||||
|
||||
void Terminate()
|
||||
{
|
||||
http::server::StopServer();
|
||||
if (serverThread) {
|
||||
CloseHandle(serverThread);
|
||||
}
|
||||
|
||||
static DWORD WINAPI ThreadProc(LPVOID lpModule)
|
||||
#ifdef BUILD_TYPE_DEBUG
|
||||
if (stdout_proxy)
|
||||
fclose(stdout_proxy);
|
||||
if (stderr_proxy)
|
||||
fclose(stderr_proxy);
|
||||
FreeConsole();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI StartHttpServer(LPVOID)
|
||||
{
|
||||
// This is a new thread so you should only initialize GWCA and setup the hook on the game thread.
|
||||
// When the game thread hook is setup (i.e. SetRenderCallback), you should do the next operations
|
||||
// on the game from within the game thread.
|
||||
|
||||
HMODULE hModule = static_cast<HMODULE>(lpModule);
|
||||
#ifdef BUILD_TYPE_DEBUG
|
||||
AllocConsole();
|
||||
SetConsoleTitleA("Daybreak.GWCA Console");
|
||||
freopen_s(&stdout_proxy, "CONOUT$", "w", stdout);
|
||||
freopen_s(&stderr_proxy, "CONOUT$", "w", stderr);
|
||||
#endif
|
||||
GW::Initialize();
|
||||
http::server::SetLogger(http::ConsoleLogger);
|
||||
http::server::Get("/alive", http::modules::HandleAlive);
|
||||
http::server::Get("/id", http::modules::HandleProcessId);
|
||||
@@ -48,31 +68,92 @@ static DWORD WINAPI ThreadProc(LPVOID lpModule)
|
||||
http::server::Get("/game", Daybreak::Modules::GameModule::GetGameInfo);
|
||||
http::server::Get("/inventory", Daybreak::Modules::InventoryModule::GetInventoryInfo);
|
||||
http::server::Get("/game/mainplayer", Daybreak::Modules::MainPlayerModule::GetMainPlayer);
|
||||
http::server::Get("/game/state", Daybreak::Modules::GameStateModule::GetGameStateInfo);
|
||||
http::server::Get("/session", Daybreak::Modules::SessionModule::GetSessionInfo);
|
||||
http::server::Get("/name", Daybreak::Modules::NameModule::GetName);
|
||||
http::server::Get("/entities/name", Daybreak::Modules::EntityNameModule::GetName);
|
||||
http::server::Get("/items/name", Daybreak::Modules::ItemNameModule::GetName);
|
||||
http::server::StartServer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(const HWND hWnd, const UINT Message, const WPARAM wParam, const LPARAM lParam) {
|
||||
if (Message == WM_CLOSE || (Message == WM_SYSCOMMAND && wParam == SC_CLOSE)) {
|
||||
Terminate();
|
||||
}
|
||||
|
||||
return CallWindowProc(oldWndProc, hWnd, Message, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK SafeWndProc(const HWND hWnd, const UINT Message, const WPARAM wParam, const LPARAM lParam) noexcept
|
||||
{
|
||||
__try {
|
||||
return WndProc(hWnd, Message, wParam, lParam);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return CallWindowProc(oldWndProc, hWnd, Message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
void OnWindowCreated(IDirect3DDevice9*) {
|
||||
startupMutex.lock();
|
||||
if (initialized) {
|
||||
startupMutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef BUILD_TYPE_DEBUG
|
||||
if (stdout_proxy)
|
||||
fclose(stdout_proxy);
|
||||
if (stderr_proxy)
|
||||
fclose(stderr_proxy);
|
||||
FreeConsole();
|
||||
AllocConsole();
|
||||
SetConsoleTitleA("Daybreak.GWCA Console");
|
||||
freopen_s(&stdout_proxy, "CONOUT$", "w", stdout);
|
||||
freopen_s(&stderr_proxy, "CONOUT$", "w", stderr);
|
||||
#endif
|
||||
|
||||
FreeLibraryAndExitThread(hModule, EXIT_SUCCESS);
|
||||
auto handle = GW::MemoryMgr::GetGWWindowHandle();
|
||||
oldWndProc = reinterpret_cast<WNDPROC>(SetWindowLongPtrW(handle, GWL_WNDPROC, reinterpret_cast<LONG>(SafeWndProc)));
|
||||
serverThread = CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
StartHttpServer,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
startupMutex.unlock();
|
||||
initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
static DWORD WINAPI Init(LPVOID)
|
||||
{
|
||||
printf("Init: Setting up scanner\n");
|
||||
GW::Scanner::Initialize();
|
||||
printf("Init: Setting up hook base\n");
|
||||
GW::HookBase::Initialize();
|
||||
printf("Init: Setting up GWCA\n");
|
||||
if (!GW::Initialize()) {
|
||||
printf("Init: Failed to set up GWCA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Init: Enabling hooks\n");
|
||||
GW::HookBase::EnableHooks();
|
||||
printf("Init: Set up render callback\n");
|
||||
GW::Render::SetRenderCallback(OnWindowCreated);
|
||||
printf("Init: Returning success\n");
|
||||
FreeLibraryAndExitThread(dllmodule, EXIT_SUCCESS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// DLL entry point, dont do things in this thread unless you know what you are doing.
|
||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
|
||||
HANDLE handle = CreateThread(0, 0, ThreadProc, hModule, 0, 0);
|
||||
HANDLE handle = CreateThread(0, 0, Init, hModule, 0, 0);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <cstdint>
|
||||
#include <json.hpp>
|
||||
#include <payloads/GameStatePayload.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Daybreak {
|
||||
void to_json(json& j, const GameStatePayload& p) {
|
||||
j = json
|
||||
{
|
||||
{"States", p.States},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ namespace Daybreak {
|
||||
{"Level", p.Level},
|
||||
{"EntityState", p.EntityState},
|
||||
{"EntityAllegiance", p.EntityAllegiance},
|
||||
{"Health", p.Health},
|
||||
{"Energy", p.Energy}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Daybreak {
|
||||
void to_json(json& j, const SessionPayload& p) {
|
||||
j = json
|
||||
{
|
||||
{"FoedKilled", p.FoesKilled},
|
||||
{"FoesKilled", p.FoesKilled},
|
||||
{"FoesToKill", p.FoesToKill},
|
||||
{"MapId", p.MapId},
|
||||
{"InstanceTimer", p.InstanceTimer},
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <cstdint>
|
||||
#include <json.hpp>
|
||||
#include <payloads/StatePayload.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Daybreak {
|
||||
void to_json(json& j, const StatePayload& p) {
|
||||
j = json
|
||||
{
|
||||
{"Id", p.Id},
|
||||
{"PosX", p.PosX},
|
||||
{"PosY", p.PosY},
|
||||
{"State", p.State},
|
||||
{"Health", p.Health},
|
||||
{"Energy", p.Energy}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <winver.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,@VERSION_TWEAK@
|
||||
PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,@VERSION_TWEAK@
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "gwdevhub"
|
||||
VALUE "FileDescription", "Daybreak.GWCA"
|
||||
VALUE "FileVersion", "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@.@VERSION_TWEAK@"
|
||||
VALUE "InternalName", "Daybreak.GWCA"
|
||||
VALUE "LegalCopyright", ""
|
||||
VALUE "OriginalFilename", "Daybreak.GWCA.dll"
|
||||
VALUE "ProductName", "Daybreak.GWCA"
|
||||
VALUE "ProductVersion", "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@.@VERSION_TWEAK@"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 0x4B0
|
||||
END
|
||||
END
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<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
|
||||
{
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0-release-23468-02" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Configuration.Options;
|
||||
using Daybreak.Services.Logging;
|
||||
using FluentAssertions;
|
||||
using LiteDB;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NSubstitute;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Logging;
|
||||
@@ -21,7 +24,9 @@ public class JsonLoggerProviderTests
|
||||
{
|
||||
File.Delete("Daybreak.db");
|
||||
this.liteDatabase = new LiteDatabase("Daybreak.db");
|
||||
this.logsManager = new JsonLogsManager(this.liteDatabase.GetCollection<Daybreak.Models.Log>());
|
||||
var options = Substitute.For<ILiveOptions<LauncherOptions>>();
|
||||
options.Value.Returns(new LauncherOptions { PersistentLogging = true });
|
||||
this.logsManager = new JsonLogsManager(this.liteDatabase.GetCollection<Daybreak.Models.Log>(), options);
|
||||
this.loggerProvider = new CVLoggerProvider(this.logsManager);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +32,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
.github\CODEOWNERS = .github\CODEOWNERS
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak.7ZipExtractor", "Daybreak.7ZipExtractor\Daybreak.7ZipExtractor.csproj", "{CA60F9AC-A496-4DB6-970E-ECE73B051C05}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -77,6 +80,18 @@ Global
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.Build.0 = Release|x64
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x86.ActiveCfg = Release|x86
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x86.Build.0 = Release|x86
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x86.Build.0 = Debug|x64
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x86.ActiveCfg = Release|x64
|
||||
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -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))]
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Daybreak.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "DirectSong")]
|
||||
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))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, Daybreak will setup DirectSong when launching Guild Wars")]
|
||||
public bool Enabled { get; set; } = false;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -11,10 +11,6 @@ public sealed class FocusViewOptions
|
||||
[OptionName(Name = "Enabled", Description = "If true, the focus view is enabled, showing live information from the game")]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(GWCAIntegration))]
|
||||
[OptionName(Name = "GWCA Integration", Description = "If true, focus view will use the GWCA plugin to read the GuildWars memory. This should be true in almost all cases")]
|
||||
public bool GWCAIntegration { get; set; } = true;
|
||||
|
||||
[OptionName(Name = "Inventory Component Enabled", Description = "If true, the focus view will show a component with the inventory contents")]
|
||||
public bool InventoryComponentVisible { get; set; }
|
||||
|
||||
|
||||
@@ -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; } = [];
|
||||
}
|
||||
|
||||
@@ -10,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))]
|
||||
@@ -23,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))]
|
||||
@@ -43,5 +46,14 @@ public sealed class LauncherOptions
|
||||
|
||||
[JsonProperty(nameof(ModStartupTimeout))]
|
||||
[OptionName(Name = "Mod Startup Timeout", Description = "Amount of seconds that Daybreak will wait for each mod to start-up before cancelling the tasks")]
|
||||
public int ModStartupTimeout { get; set; } = 30;
|
||||
[OptionRange<double>(MinValue = 30, MaxValue = 300)]
|
||||
public double ModStartupTimeout { get; set; } = 30;
|
||||
|
||||
[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; }
|
||||
|
||||
@@ -20,4 +20,8 @@ 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 => false;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,19 @@ 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))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, Daybreak will also launch GWToolboxdll when launching GuildWars")]
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
[JsonProperty(nameof(StartupDelay))]
|
||||
[OptionName(Name = "Startup Delay", Description = "Amount of seconds that Daybreak will wait for GWToolbox to start before continuing with the other mods")]
|
||||
[OptionRange<double>(MinValue = 1, MaxValue = 10)]
|
||||
public double StartupDelay { get; set; } = 1;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@ namespace Daybreak.Configuration.Options;
|
||||
[OptionsName(Name = "uMod")]
|
||||
public sealed class UModOptions
|
||||
{
|
||||
[JsonProperty(nameof(DllPath))]
|
||||
[OptionName(Name = "Dll Path", Description = "The path to the uMod dll")]
|
||||
public string? DllPath { get; set; }
|
||||
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, Daybreak will also launch uMod when launching GuildWars")]
|
||||
public bool Enabled { get; set; }
|
||||
@@ -22,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; } = [];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
using Daybreak.Services.Credentials;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
@@ -71,7 +70,6 @@ using Daybreak.Services.Events;
|
||||
using Daybreak.Controls;
|
||||
using Daybreak.Models.Plugins;
|
||||
using Daybreak.Services.Plugins;
|
||||
using Daybreak.Services.UMod.Utilities;
|
||||
using Daybreak.Services.Toolbox.Utilities;
|
||||
using Daybreak.Services.Injection;
|
||||
using Daybreak.Services.ReShade;
|
||||
@@ -80,6 +78,10 @@ using Daybreak.Services.LaunchConfigurations;
|
||||
using Daybreak.Services.ExecutableManagement;
|
||||
using Daybreak.Views.Launch;
|
||||
using Daybreak.Services.GWCA;
|
||||
using Daybreak.Services.DirectSong;
|
||||
using Daybreak.Views.Onboarding.DirectSong;
|
||||
using Daybreak.Services.SevenZip;
|
||||
using Daybreak.Services.ReShade.Notifications;
|
||||
|
||||
namespace Daybreak.Configuration;
|
||||
|
||||
@@ -97,8 +99,8 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
.WithMessageHandler(this.SetupLoggingAndMetrics<ApplicationUpdater>)
|
||||
.WithDefaultRequestHeadersSetup(this.SetupDaybreakUserAgent)
|
||||
.Build()
|
||||
.RegisterHttpClient<BloogumClient>()
|
||||
.WithMessageHandler(this.SetupLoggingAndMetrics<BloogumClient>)
|
||||
.RegisterHttpClient<OnlinePictureClient>()
|
||||
.WithMessageHandler(this.SetupLoggingAndMetrics<OnlinePictureClient>)
|
||||
.WithDefaultRequestHeadersSetup(this.SetupChromeImpersonationUserAgent)
|
||||
.Build()
|
||||
.RegisterHttpClient<GraphClient>()
|
||||
@@ -149,6 +151,10 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
.WithMessageHandler(this.SetupLoggingAndMetrics<GWCAClient>)
|
||||
.WithDefaultRequestHeadersSetup(this.SetupDaybreakUserAgent)
|
||||
.WithTimeout(TimeSpan.FromSeconds(5))
|
||||
.Build()
|
||||
.RegisterHttpClient<UModService>()
|
||||
.WithMessageHandler(this.SetupLoggingAndMetrics<UModService>)
|
||||
.WithDefaultRequestHeadersSetup(this.SetupDaybreakUserAgent)
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -176,6 +182,7 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
services.AddSingleton<ViewManager>();
|
||||
services.AddSingleton<ProcessorUsageMonitor>();
|
||||
services.AddSingleton<MemoryUsageMonitor>();
|
||||
services.AddSingleton<DiskUsageMonitor>();
|
||||
services.AddSingleton<IViewManager, ViewManager>(sp => sp.GetRequiredService<ViewManager>());
|
||||
services.AddSingleton<IViewProducer, ViewManager>(sp => sp.GetRequiredService<ViewManager>());
|
||||
services.AddSingleton<PostUpdateActionManager>();
|
||||
@@ -208,25 +215,27 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
services.AddSingleton<IPluginsService, PluginsService>();
|
||||
services.AddSingleton<ISplashScreenService, SplashScreenService>();
|
||||
services.AddSingleton<IGuildWarsExecutableManager, GuildWarsExecutableManager>();
|
||||
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>();
|
||||
services.AddScoped<IBloogumClient, BloogumClient>();
|
||||
services.AddScoped<IOnlinePictureClient, OnlinePictureClient>();
|
||||
services.AddScoped<IApplicationUpdater, ApplicationUpdater>();
|
||||
services.AddScoped<IBuildTemplateManager, BuildTemplateManager>();
|
||||
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<IMemoryScanner, MemoryScanner>();
|
||||
services.AddScoped<IExperienceCalculator, ExperienceCalculator>();
|
||||
services.AddScoped<IAttributePointCalculator, AttributePointCalculator>();
|
||||
services.AddScoped<IDownloadService, DownloadService>();
|
||||
services.AddScoped<IGuildwarsInstaller, GuildwarsInstaller>();
|
||||
services.AddScoped<IGuildwarsEntityDebouncer, GuildwarsEntityDebouncer>();
|
||||
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>>();
|
||||
@@ -241,16 +250,9 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
services.AddScoped<IRegistryService, RegistryService>();
|
||||
services.AddScoped<IEventNotifierService, EventNotifierService>();
|
||||
services.AddScoped<IBackgroundProvider, BackgroundProvider>();
|
||||
services.AddScoped<IUModClient, UModClient>();
|
||||
services.AddScoped<IToolboxClient, ToolboxClient>();
|
||||
services.AddScoped<IProcessInjector, ProcessInjector>();
|
||||
services.AddScoped<ILaunchConfigurationService, LaunchConfigurationService>();
|
||||
services.AddScoped<IGWCAClient, GWCAClient>();
|
||||
|
||||
//TODO: Composite will be the main reader. Composite will select between GuildwarsMemoryReader and GWCAMemoryReader depending on the options. Remove once GWCA is stable
|
||||
services.AddScoped<IGuildwarsMemoryReader, CompositeMemoryReader>();
|
||||
services.AddScoped<GuildwarsMemoryReader>();
|
||||
services.AddScoped<GWCAMemoryReader>();
|
||||
}
|
||||
|
||||
public override void RegisterViews(IViewProducer viewProducer)
|
||||
@@ -293,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>();
|
||||
@@ -312,6 +316,11 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
viewProducer.RegisterView<ReShadePresetView>();
|
||||
viewProducer.RegisterView<LaunchConfigurationView>();
|
||||
viewProducer.RegisterView<LaunchConfigurationsView>();
|
||||
viewProducer.RegisterView<DirectSongInstallationView>();
|
||||
viewProducer.RegisterView<DirectSongInstallationChoiceView>();
|
||||
viewProducer.RegisterView<DirectSongOnboardingEntryView>();
|
||||
viewProducer.RegisterView<DirectSongSwitchView>();
|
||||
viewProducer.RegisterView<SettingsSynchronizationView>();
|
||||
}
|
||||
|
||||
public override void RegisterStartupActions(IStartupActionProducer startupActionProducer)
|
||||
@@ -320,6 +329,7 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
|
||||
startupActionProducer.RegisterAction<RenameInstallerAction>();
|
||||
startupActionProducer.RegisterAction<FixSymbolicLinkStartupAction>();
|
||||
startupActionProducer.RegisterAction<UpdateUModAction>();
|
||||
}
|
||||
|
||||
public override void RegisterPostUpdateActions(IPostUpdateActionProducer postUpdateActionProducer)
|
||||
@@ -384,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>();
|
||||
@@ -412,6 +422,7 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
optionsProducer.RegisterOptions<GuildwarsExecutableOptions>();
|
||||
optionsProducer.RegisterOptions<CredentialManagerOptions>();
|
||||
optionsProducer.RegisterOptions<LaunchConfigurationServiceOptions>();
|
||||
optionsProducer.RegisterOptions<DirectSongOptions>();
|
||||
}
|
||||
|
||||
public override void RegisterNotificationHandlers(INotificationHandlerProducer notificationHandlerProducer)
|
||||
@@ -421,16 +432,18 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
notificationHandlerProducer.RegisterNotificationHandler<TradeMessageNotificationHandler>();
|
||||
notificationHandlerProducer.RegisterNotificationHandler<FixSymbolicLinkNotificationHandler>();
|
||||
notificationHandlerProducer.RegisterNotificationHandler<UpdateNotificationHandler>();
|
||||
notificationHandlerProducer.RegisterNotificationHandler<ReShadeConfigChangedHandler>();
|
||||
}
|
||||
|
||||
public override void RegisterMods(IModsManager modsManager)
|
||||
{
|
||||
modsManager.RegisterMod<IToolboxService, ToolboxService>();
|
||||
modsManager.RegisterMod<IReShadeService, ReShadeService>();
|
||||
modsManager.RegisterMod<IUModService, UModService>();
|
||||
modsManager.RegisterMod<IToolboxService, ToolboxService>();
|
||||
modsManager.RegisterMod<IDSOALService, DSOALService>();
|
||||
modsManager.RegisterMod<IGuildwarsScreenPlacer, GuildwarsScreenPlacer>();
|
||||
modsManager.RegisterMod<IReShadeService, ReShadeService>();
|
||||
modsManager.RegisterMod<IGWCAInjector, GWCAInjector>();
|
||||
modsManager.RegisterMod<IDirectSongService, DirectSongService>(singleton: true);
|
||||
}
|
||||
|
||||
private void RegisterLiteCollections(IServiceCollection services)
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ public partial class LivingEntityContextMenu : UserControl
|
||||
{
|
||||
private readonly IGuildwarsMemoryReader guildwarsMemoryReader;
|
||||
|
||||
public event EventHandler<LivingEntity?>? LivingEntityContextMenuClicked;
|
||||
public event EventHandler<(LivingEntity? Entity, string? Name)>? LivingEntityContextMenuClicked;
|
||||
public event EventHandler<Profession?>? LivingEntityProfessionContextMenuClicked;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
@@ -59,12 +59,12 @@ public partial class LivingEntityContextMenu : UserControl
|
||||
}
|
||||
|
||||
await this.guildwarsMemoryReader.EnsureInitialized(context.GuildWarsApplicationLaunchContext!.GuildWarsProcess, CancellationToken.None);
|
||||
this.EntityName = await this.guildwarsMemoryReader.GetNamedEntity(context.LivingEntity!, CancellationToken.None);
|
||||
this.EntityName = await this.guildwarsMemoryReader.GetEntityName(context.LivingEntity!, CancellationToken.None).ConfigureAwait(true);
|
||||
}
|
||||
|
||||
private void NpcDefinitionTextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
{
|
||||
this.LivingEntityContextMenuClicked?.Invoke(this, this.DataContext.As<LivingEntityContextMenuContext>()?.LivingEntity ?? default);
|
||||
this.LivingEntityContextMenuClicked?.Invoke(this, (this.DataContext.As<LivingEntityContextMenuContext>()?.LivingEntity ?? default, this.EntityName));
|
||||
}
|
||||
|
||||
private void PrimaryProfessionTextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
|
||||
@@ -147,6 +147,13 @@
|
||||
Cursor="Hand"
|
||||
Clicked="ReShadeButton_Clicked"
|
||||
ToolTip="Open ReShade manager"/>
|
||||
<buttons:MenuButton Title="DirectSong"
|
||||
Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
|
||||
HighlightColor="{DynamicResource MahApps.Brushes.Accent}"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="DirectSongButton_Clicked"
|
||||
ToolTip="Open DirectSong manager"/>
|
||||
</local:ExpandableMenuSection.Children>
|
||||
</local:ExpandableMenuSection>
|
||||
<local:ExpandableMenuSection
|
||||
|
||||
@@ -5,6 +5,7 @@ using Daybreak.Services.Notifications;
|
||||
using Daybreak.Views;
|
||||
using Daybreak.Views.Copy;
|
||||
using Daybreak.Views.Launch;
|
||||
using Daybreak.Views.Onboarding.DirectSong;
|
||||
using Daybreak.Views.Onboarding.DSOAL;
|
||||
using Daybreak.Views.Onboarding.ReShade;
|
||||
using Daybreak.Views.Onboarding.Toolbox;
|
||||
@@ -127,6 +128,11 @@ public partial class MenuList : UserControl
|
||||
this.viewManager.ShowView<ReShadeOnboardingEntryView>();
|
||||
}
|
||||
|
||||
private void DirectSongButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<DirectSongOnboardingEntryView>();
|
||||
}
|
||||
|
||||
private void KamadanButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<KamadanTradeChatView>();
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using Daybreak.Services.Scanner;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Core.Extensions;
|
||||
using System.Windows.Input;
|
||||
@@ -43,10 +42,9 @@ 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 IGuildwarsEntityDebouncer guildwarsEntityDebouncer;
|
||||
private readonly IThemeManager themeManager;
|
||||
private readonly Color outlineColor = Colors.Chocolate;
|
||||
private readonly TimeSpan offsetRevertDelay = TimeSpan.FromSeconds(3);
|
||||
@@ -65,7 +63,6 @@ public partial class GuildwarsMinimap : UserControl
|
||||
private Point initialClickPoint = new(0, 0);
|
||||
private Point lastPathfindingPoint = new(0, 0);
|
||||
private int pathfindingObjectiveCount = 0;
|
||||
private DebounceResponse? cachedDebounceResponse;
|
||||
private PathfindingCache? pathfindingCache;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
@@ -73,6 +70,8 @@ public partial class GuildwarsMinimap : UserControl
|
||||
[GenerateDependencyProperty]
|
||||
private GameData gameData = new();
|
||||
[GenerateDependencyProperty]
|
||||
private GameState gameState = new();
|
||||
[GenerateDependencyProperty]
|
||||
private double zoom = 0.08;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool drawPositionHistory = true;
|
||||
@@ -91,12 +90,12 @@ public partial class GuildwarsMinimap : UserControl
|
||||
public event EventHandler<PlayerInformation>? PlayerInformationClicked;
|
||||
public event EventHandler<MapIcon>? MapIconClicked;
|
||||
public event EventHandler<Profession>? ProfessionClicked;
|
||||
public event EventHandler<string?>? NpcNameClicked;
|
||||
|
||||
public GuildwarsMinimap()
|
||||
:this(
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IPathfinder>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IDrawingService>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IGuildwarsEntityDebouncer>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IThemeManager>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IMetricsService>())
|
||||
{
|
||||
@@ -105,13 +104,11 @@ public partial class GuildwarsMinimap : UserControl
|
||||
public GuildwarsMinimap(
|
||||
IPathfinder pathfinder,
|
||||
IDrawingService drawingService,
|
||||
IGuildwarsEntityDebouncer guildwarsEntityDebouncer,
|
||||
IThemeManager themeManager,
|
||||
IMetricsService metricsService)
|
||||
{
|
||||
this.pathfinder = pathfinder.ThrowIfNull();
|
||||
this.drawingService = drawingService.ThrowIfNull();
|
||||
this.guildwarsEntityDebouncer = guildwarsEntityDebouncer.ThrowIfNull();
|
||||
this.themeManager = themeManager.ThrowIfNull();
|
||||
this.drawingLatency = metricsService.CreateHistogram<double>(DrawingLatencyName, DrawingLatencyUnitName, DrawingLatencyDescription, Models.Metrics.AggregationTypes.P95);
|
||||
|
||||
@@ -135,7 +132,6 @@ public partial class GuildwarsMinimap : UserControl
|
||||
}
|
||||
else if (e.Property == PathingDataProperty)
|
||||
{
|
||||
this.guildwarsEntityDebouncer.ClearCaches();
|
||||
this.mainPlayerPositionHistory.Clear();
|
||||
this.lastPathfindingPoint = new Point(0, 0);
|
||||
this.pathfindingObjectiveCount = 0;
|
||||
@@ -146,13 +142,53 @@ public partial class GuildwarsMinimap : UserControl
|
||||
{
|
||||
this.UpdateGameData();
|
||||
}
|
||||
else if (e.Property == GameDataProperty &&
|
||||
this.GameData.Valid)
|
||||
else if (e.Property == GameStateProperty &&
|
||||
this.GameState is not null)
|
||||
{
|
||||
this.UpdateStates();
|
||||
this.UpdateGameData();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStates()
|
||||
{
|
||||
if (this.GameState is null ||
|
||||
this.GameData is null ||
|
||||
this.GameData.Valid is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mainPlayerState = this.GameState.States?.FirstOrDefault(state => state.Id == this.GameData.MainPlayer?.Id);
|
||||
this.GameData.MainPlayer!.Position = mainPlayerState?.Position ?? new Position();
|
||||
this.GameData.MainPlayer!.CurrentHealth = mainPlayerState?.Health ?? 0;
|
||||
this.GameData.MainPlayer!.CurrentEnergy = mainPlayerState?.Energy ?? 0;
|
||||
foreach (var worldPlayer in this.GameData.WorldPlayers!)
|
||||
{
|
||||
var worldPlayerState = this.GameState.States?.FirstOrDefault(state => state.Id == worldPlayer.Id);
|
||||
worldPlayer.Position = worldPlayerState?.Position ?? new Position();
|
||||
worldPlayer.CurrentHealth = worldPlayerState?.Health ?? 0;
|
||||
worldPlayer.CurrentEnergy = worldPlayerState?.Energy ?? 0;
|
||||
}
|
||||
|
||||
foreach (var partyPlayer in this.GameData.Party!)
|
||||
{
|
||||
var partyPlayerState = this.GameState.States?.FirstOrDefault(state => state.Id == partyPlayer.Id);
|
||||
partyPlayer.Position = partyPlayerState?.Position ?? new Position();
|
||||
partyPlayer.CurrentHealth = partyPlayerState?.Health ?? 0;
|
||||
partyPlayer.CurrentEnergy = partyPlayerState?.Energy ?? 0;
|
||||
}
|
||||
|
||||
foreach (var entity in this.GameData.LivingEntities!)
|
||||
{
|
||||
var state = this.GameState.States?.FirstOrDefault(state => state.Id == entity.Id);
|
||||
entity.Position = state?.Position ?? new Position();
|
||||
entity.State = state?.State ?? LivingEntityState.Unknown;
|
||||
entity.Health = state?.Health ?? 0;
|
||||
entity.Energy = state?.Energy ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateGameData()
|
||||
{
|
||||
if(this.GameData is null ||
|
||||
@@ -161,12 +197,11 @@ public partial class GuildwarsMinimap : UserControl
|
||||
return;
|
||||
}
|
||||
|
||||
var debounceResponse = this.guildwarsEntityDebouncer.DebounceEntities(this.GameData);
|
||||
if (!double.IsFinite(this.mapWidth) ||
|
||||
!double.IsFinite(this.mapHeight) ||
|
||||
!double.IsFinite(this.mapVirtualMinWidth) ||
|
||||
!double.IsFinite(this.mapVirtualMinHeight) ||
|
||||
debounceResponse.MainPlayer.Position is null)
|
||||
this.GameData.MainPlayer?.Position is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -175,7 +210,7 @@ public partial class GuildwarsMinimap : UserControl
|
||||
this.TargetEntityModelId = (int?)this.GameData.LivingEntities?.FirstOrDefault(e => e.Id == this.TargetEntityId)?.ModelType ?? 0;
|
||||
var screenVirtualWidth = this.ActualWidth / this.Zoom;
|
||||
var screenVirtualHeight = this.ActualHeight / this.Zoom;
|
||||
var position = debounceResponse.MainPlayer.Position!.Value;
|
||||
var position = this.GameData?.MainPlayer?.Position ?? new Position();
|
||||
this.originPoint = new Point(
|
||||
position.X - (screenVirtualWidth / 2) - (this.originOffset.X / this.Zoom),
|
||||
position.Y + (screenVirtualHeight / 2) + (this.originOffset.Y / this.Zoom));
|
||||
@@ -189,19 +224,18 @@ public partial class GuildwarsMinimap : UserControl
|
||||
0);
|
||||
this.MapDrawingHost.Height = this.mapHeight * this.Zoom;
|
||||
this.MapDrawingHost.Width = this.mapWidth * this.Zoom;
|
||||
this.cachedDebounceResponse = debounceResponse;
|
||||
this.ManageMainPlayerPositionHistory();
|
||||
this.DrawEntities();
|
||||
}
|
||||
|
||||
private void ManageMainPlayerPositionHistory()
|
||||
{
|
||||
if (this.cachedDebounceResponse is null)
|
||||
if (this.GameData is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var currentPosition = this.cachedDebounceResponse.MainPlayer.Position ?? throw new InvalidOperationException("Unexpected main player null position");
|
||||
var currentPosition = this.GameData?.MainPlayer?.Position ?? throw new InvalidOperationException("Unexpected main player null position");
|
||||
if (this.mainPlayerPositionHistory.Any(oldPosition => PositionsCollide(oldPosition, currentPosition)))
|
||||
{
|
||||
return;
|
||||
@@ -320,12 +354,12 @@ public partial class GuildwarsMinimap : UserControl
|
||||
PositionRadius,
|
||||
EntitySize,
|
||||
foregroundColor);
|
||||
this.drawingService.DrawEngagementArea(bitmap, this.cachedDebounceResponse ?? new DebounceResponse());
|
||||
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.DrawEntities(bitmap, this.cachedDebounceResponse ?? new DebounceResponse(), this.TargetEntityId);
|
||||
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);
|
||||
}
|
||||
@@ -387,8 +421,8 @@ public partial class GuildwarsMinimap : UserControl
|
||||
|
||||
var playerPosition = new Point
|
||||
{
|
||||
X = this.cachedDebounceResponse?.MainPlayer.Position?.X ?? 0,
|
||||
Y = this.cachedDebounceResponse?.MainPlayer.Position?.Y ?? 0,
|
||||
X = this.GameData?.MainPlayer?.Position?.X ?? 0,
|
||||
Y = this.GameData?.MainPlayer?.Position?.Y ?? 0,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -595,7 +629,8 @@ public partial class GuildwarsMinimap : UserControl
|
||||
|
||||
private void GuildwarsMinimap_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (this.GameData.Valid is false ||
|
||||
if (this.GameData is null ||
|
||||
this.GameData.Valid is false ||
|
||||
this.GameData.MainPlayer is null ||
|
||||
this.GameData.Party is null ||
|
||||
this.GameData.WorldPlayers is null)
|
||||
@@ -619,24 +654,24 @@ public partial class GuildwarsMinimap : UserControl
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.LivingEntities!.OfType<IEntity>()) is not null)
|
||||
if (this.CheckMouseOverEntity(this.GameData.LivingEntities?.OfType<IEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.MapIcons!.OfType<IPositionalEntity>()) is not null)
|
||||
if (this.CheckMouseOverEntity(this.GameData.MapIcons?.OfType<IPositionalEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.MainPlayer.QuestLog!
|
||||
if (this.CheckMouseOverEntity(this.GameData.MainPlayer.QuestLog?
|
||||
.Where(entity => this.drawingService.IsEntityOnScreen(entity.Position, out _, out _))
|
||||
.OfType<IPositionalEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.MainPlayer.QuestLog!
|
||||
if (this.CheckMouseOverEntity(this.GameData.MainPlayer.QuestLog?
|
||||
.Where(entity => !this.drawingService.IsEntityOnScreen(entity.Position, out _, out _))
|
||||
.Select(oldQuestMetadata =>
|
||||
{
|
||||
@@ -689,24 +724,36 @@ public partial class GuildwarsMinimap : UserControl
|
||||
this.QuestMetadataClicked?.Invoke(this, quest);
|
||||
}
|
||||
|
||||
private void PlayerContextMenu_PlayerContextMenuClicked(object _, PlayerInformation? playerInformation)
|
||||
private void PlayerContextMenu_PlayerContextMenuClicked(object _, (PlayerInformation? Player, string? Name) tuple)
|
||||
{
|
||||
if (playerInformation is null)
|
||||
if (tuple.Name?.IsNullOrWhiteSpace() is false)
|
||||
{
|
||||
this.NpcNameClicked?.Invoke(this, tuple.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tuple.Player is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.PlayerInformationClicked?.Invoke(this, playerInformation);
|
||||
this.PlayerInformationClicked?.Invoke(this, tuple.Player);
|
||||
}
|
||||
|
||||
private void LivingEntityContextMenu_LivingEntityContextMenuClicked(object _, LivingEntity? livingEntity)
|
||||
private void LivingEntityContextMenu_LivingEntityContextMenuClicked(object _, (LivingEntity? LivingEntity, string? Name) tuple)
|
||||
{
|
||||
if (livingEntity is null)
|
||||
if (tuple.Name?.IsNullOrWhiteSpace() is false)
|
||||
{
|
||||
this.NpcNameClicked?.Invoke(this, tuple.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tuple.LivingEntity is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.LivingEntityClicked?.Invoke(this, livingEntity);
|
||||
this.LivingEntityClicked?.Invoke(this, tuple.LivingEntity);
|
||||
}
|
||||
|
||||
private void LivingEntityContextMenu_LivingEntityProfessionContextMenuClicked(object _, Profession? e)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -18,7 +18,7 @@ public partial class PlayerContextMenu : UserControl
|
||||
{
|
||||
private readonly IGuildwarsMemoryReader guildwarsMemoryReader;
|
||||
|
||||
public event EventHandler<PlayerInformation?>? PlayerContextMenuClicked;
|
||||
public event EventHandler<(PlayerInformation? Player, string? Name)>? PlayerContextMenuClicked;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string playerName = string.Empty;
|
||||
@@ -44,11 +44,11 @@ public partial class PlayerContextMenu : UserControl
|
||||
}
|
||||
|
||||
await this.guildwarsMemoryReader.EnsureInitialized(context.GuildWarsApplicationLaunchContext!.GuildWarsProcess, CancellationToken.None);
|
||||
this.PlayerName = await this.guildwarsMemoryReader.GetNamedEntity(context.Player!, CancellationToken.None);
|
||||
this.PlayerName = await this.guildwarsMemoryReader.GetEntityName(context.Player!, CancellationToken.None).ConfigureAwait(true);
|
||||
}
|
||||
|
||||
private void TextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
{
|
||||
this.PlayerContextMenuClicked?.Invoke(this, this.DataContext.As<PlayerContextMenuContext>()?.Player ?? default);
|
||||
this.PlayerContextMenuClicked?.Invoke(this, (this.DataContext.As<PlayerContextMenuContext>()?.Player ?? default, this.PlayerName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<UserControl x:Class="Daybreak.Controls.SnowfallOverlay"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:effects="clr-namespace:System.Windows.Media.Extensions.Effects;assembly=WpfExtended"
|
||||
xmlns:converters="clr-namespace:Daybreak.Converters"
|
||||
mc:Ignorable="d"
|
||||
Loaded="UserControl_Loaded"
|
||||
Unloaded="UserControl_Unloaded"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<converters:DoubleMultiplierConverter x:Key="FallMultiplier1" Multiplier="0.2"/>
|
||||
<converters:DoubleMultiplierConverter x:Key="FallMultiplier2" Multiplier="0.18"/>
|
||||
<converters:DoubleMultiplierConverter x:Key="FallMultiplier3" Multiplier="0.15"/>
|
||||
<converters:DoubleMultiplierConverter x:Key="FallMultiplier4" Multiplier="0.13"/>
|
||||
<converters:DoubleMultiplierConverter x:Key="FallMultiplier5" Multiplier="0.1"/>
|
||||
</UserControl.Resources>
|
||||
<UserControl.Effect>
|
||||
<BlurEffect
|
||||
KernelType="Box"
|
||||
Radius="2"/>
|
||||
</UserControl.Effect>
|
||||
<UserControl.Triggers>
|
||||
<EventTrigger RoutedEvent="UserControl.Loaded">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="_this"
|
||||
Storyboard.TargetProperty="Time"
|
||||
From="0"
|
||||
To="1000"
|
||||
Duration="0:30:0"
|
||||
RepeatBehavior="Forever"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</UserControl.Triggers>
|
||||
<Grid>
|
||||
<Grid>
|
||||
<Grid.Background>
|
||||
<ImageBrush x:Name="Host1"
|
||||
TileMode="Tile"
|
||||
ViewportUnits="Absolute"
|
||||
Viewport="0, 0, 100, 100">
|
||||
<ImageBrush.RelativeTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="{Binding ElementName=_this, Path=FlakeSize1, Mode=OneWay}" ScaleY="{Binding ElementName=_this, Path=FlakeSize1, Mode=OneWay}" />
|
||||
<TranslateTransform x:Name="SnowfallTransform1"
|
||||
X="0"
|
||||
Y="{Binding ElementName=_this, Path=Time, Mode=OneWay, Converter={StaticResource FallMultiplier1}}" />
|
||||
</TransformGroup>
|
||||
</ImageBrush.RelativeTransform>
|
||||
</ImageBrush>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.Background>
|
||||
<ImageBrush x:Name="Host2"
|
||||
TileMode="Tile"
|
||||
ViewportUnits="Absolute"
|
||||
Viewport="0, 0, 100, 100">
|
||||
<ImageBrush.RelativeTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="{Binding ElementName=_this, Path=FlakeSize2, Mode=OneWay}" ScaleY="{Binding ElementName=_this, Path=FlakeSize2, Mode=OneWay}" />
|
||||
<TranslateTransform x:Name="SnowfallTransform2"
|
||||
X="0"
|
||||
Y="{Binding ElementName=_this, Path=Time, Mode=OneWay, Converter={StaticResource FallMultiplier2}}" />
|
||||
</TransformGroup>
|
||||
</ImageBrush.RelativeTransform>
|
||||
</ImageBrush>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.Background>
|
||||
<ImageBrush x:Name="Host3"
|
||||
TileMode="Tile"
|
||||
ViewportUnits="Absolute"
|
||||
Viewport="0, 0, 100, 100">
|
||||
<ImageBrush.RelativeTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="{Binding ElementName=_this, Path=FlakeSize3, Mode=OneWay}" ScaleY="{Binding ElementName=_this, Path=FlakeSize3, Mode=OneWay}" />
|
||||
<TranslateTransform x:Name="SnowfallTransform3"
|
||||
X="0"
|
||||
Y="{Binding ElementName=_this, Path=Time, Mode=OneWay, Converter={StaticResource FallMultiplier3}}" />
|
||||
</TransformGroup>
|
||||
</ImageBrush.RelativeTransform>
|
||||
</ImageBrush>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.Background>
|
||||
<ImageBrush x:Name="Host4"
|
||||
TileMode="Tile"
|
||||
ViewportUnits="Absolute"
|
||||
Viewport="0, 0, 100, 100">
|
||||
<ImageBrush.RelativeTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="{Binding ElementName=_this, Path=FlakeSize4, Mode=OneWay}" ScaleY="{Binding ElementName=_this, Path=FlakeSize4, Mode=OneWay}" />
|
||||
<TranslateTransform x:Name="SnowfallTransform4"
|
||||
X="0"
|
||||
Y="{Binding ElementName=_this, Path=Time, Mode=OneWay, Converter={StaticResource FallMultiplier4}}" />
|
||||
</TransformGroup>
|
||||
</ImageBrush.RelativeTransform>
|
||||
</ImageBrush>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.Background>
|
||||
<ImageBrush x:Name="Host5"
|
||||
TileMode="Tile"
|
||||
ViewportUnits="Absolute"
|
||||
Viewport="0, 0, 100, 100">
|
||||
<ImageBrush.RelativeTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="{Binding ElementName=_this, Path=FlakeSize5, Mode=OneWay}" ScaleY="{Binding ElementName=_this, Path=FlakeSize5, Mode=OneWay}" />
|
||||
<TranslateTransform x:Name="SnowfallTransform5"
|
||||
X="0"
|
||||
Y="{Binding ElementName=_this, Path=Time, Mode=OneWay, Converter={StaticResource FallMultiplier5}}" />
|
||||
</TransformGroup>
|
||||
</ImageBrush.RelativeTransform>
|
||||
</ImageBrush>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
/// <summary>
|
||||
/// Interaction logic for SnowfallOverlay.xaml
|
||||
/// </summary>
|
||||
public partial class SnowfallOverlay : UserControl
|
||||
{
|
||||
private static readonly double[] Frequencies = new double[] { 0.1, 0.025, 1, 0.25 };
|
||||
private static readonly double[] Amplitudes = new double[] { 1, 0.1, 0.1, 0.2 };
|
||||
private static readonly double Divisor = Amplitudes.Sum();
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private double flakeSize1;
|
||||
[GenerateDependencyProperty]
|
||||
private double flakeSize2;
|
||||
[GenerateDependencyProperty]
|
||||
private double flakeSize3;
|
||||
[GenerateDependencyProperty]
|
||||
private double flakeSize4;
|
||||
[GenerateDependencyProperty]
|
||||
private double flakeSize5;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private double time;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private double windStrength1;
|
||||
[GenerateDependencyProperty]
|
||||
private double windStrength2;
|
||||
[GenerateDependencyProperty]
|
||||
private double windStrength3;
|
||||
[GenerateDependencyProperty]
|
||||
private double windStrength4;
|
||||
[GenerateDependencyProperty]
|
||||
private double windStrength5;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private double baseWind1;
|
||||
[GenerateDependencyProperty]
|
||||
private double baseWind2;
|
||||
[GenerateDependencyProperty]
|
||||
private double baseWind3;
|
||||
[GenerateDependencyProperty]
|
||||
private double baseWind4;
|
||||
[GenerateDependencyProperty]
|
||||
private double baseWind5;
|
||||
|
||||
private CancellationTokenSource? tokenSource;
|
||||
|
||||
public SnowfallOverlay()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.InitializeImages();
|
||||
}
|
||||
|
||||
private void InitializeImages()
|
||||
{
|
||||
using var snowTexture1 = this.GetType().Assembly.GetManifestResourceStream("Daybreak.Resources.Snow1.png");
|
||||
using var snowTexture2 = this.GetType().Assembly.GetManifestResourceStream("Daybreak.Resources.Snow2.png");
|
||||
using var snowTexture3 = this.GetType().Assembly.GetManifestResourceStream("Daybreak.Resources.Snow3.png");
|
||||
using var snowTexture4 = this.GetType().Assembly.GetManifestResourceStream("Daybreak.Resources.Snow4.png");
|
||||
var bitmap1 = BitmapFactory.FromStream(snowTexture1);
|
||||
var bitmap2 = BitmapFactory.FromStream(snowTexture2);
|
||||
var bitmap3 = BitmapFactory.FromStream(snowTexture3);
|
||||
var bitmap4 = BitmapFactory.FromStream(snowTexture4);
|
||||
this.Host1.ImageSource = bitmap4;
|
||||
this.Host2.ImageSource = bitmap3;
|
||||
this.Host3.ImageSource = bitmap2;
|
||||
this.Host4.ImageSource = bitmap1;
|
||||
this.Host5.ImageSource = bitmap1;
|
||||
}
|
||||
|
||||
private async void SimulateWind(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var time = this.Time;
|
||||
this.SnowfallTransform1.X += (this.BaseWind1 + (this.GetNoise(time) * this.WindStrength1)) / this.FlakeSize1;
|
||||
this.SnowfallTransform2.X += (this.BaseWind2 + (this.GetNoise(time - 0.02) * this.WindStrength2)) / this.FlakeSize2;
|
||||
this.SnowfallTransform3.X += (this.BaseWind3 + (this.GetNoise(time - 0.03) * this.WindStrength3)) / this.FlakeSize3;
|
||||
this.SnowfallTransform4.X += (this.BaseWind4 + (this.GetNoise(time - 0.05) * this.WindStrength4)) / this.FlakeSize4;
|
||||
this.SnowfallTransform5.X += (this.BaseWind5 + (this.GetNoise(time - 0.08) * this.WindStrength5)) / this.FlakeSize5;
|
||||
await Task.Delay(16, cancellationToken).ConfigureAwait(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void UserControl_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.tokenSource?.Dispose();
|
||||
this.tokenSource = new CancellationTokenSource();
|
||||
this.SimulateWind(this.tokenSource.Token);
|
||||
}
|
||||
|
||||
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.tokenSource?.Dispose();
|
||||
this.tokenSource = default;
|
||||
}
|
||||
|
||||
private double GetNoise(double source)
|
||||
{
|
||||
var returnValue = 0d;
|
||||
for(var i = 0; i < Frequencies.Length; i++)
|
||||
{
|
||||
var f = Frequencies[i];
|
||||
var a = Amplitudes[i];
|
||||
returnValue += a * Math.Sin(f * source * Math.PI);
|
||||
}
|
||||
|
||||
return returnValue / Divisor;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
@@ -31,7 +30,6 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock FontSize="16" Text="Username:" Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="5" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Password:" Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="5" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Character name:" Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="5" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
|
||||
<TextBox Text="{Binding ElementName=_this, Path=Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Background="Transparent"
|
||||
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1"
|
||||
FontSize="16" TextChanged="UsernameTextbox_TextChanged" Margin="5"
|
||||
@@ -40,10 +38,6 @@
|
||||
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="1" Grid.Column="1"
|
||||
FontSize="16" PasswordChanged="Passwordbox_PasswordChanged" Margin="5"
|
||||
ToolTip="Password" />
|
||||
<TextBox Text="{Binding ElementName=_this, Path=CharacterName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Background="Transparent"
|
||||
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="2" Grid.Column="1"
|
||||
FontSize="16" TextChanged="CharacterNameTextbox_TextChanged" Margin="5"
|
||||
ToolTip="Character name" />
|
||||
</Grid>
|
||||
<buttons:BinButton Grid.Column="2" Height="30" Width="30" Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" VerticalAlignment="Center" Margin="5, 5, 5, 5"
|
||||
Clicked="BinButton_Clicked"
|
||||
|
||||
@@ -21,8 +21,6 @@ public partial class AccountTemplate : UserControl
|
||||
private string username = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private string password = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private string characterName = string.Empty;
|
||||
|
||||
public AccountTemplate()
|
||||
{
|
||||
@@ -36,7 +34,6 @@ public partial class AccountTemplate : UserControl
|
||||
{
|
||||
this.PasswordBox.Password = loginCredentials.Password;
|
||||
this.Username = loginCredentials.Username;
|
||||
this.CharacterName = loginCredentials.CharacterName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,11 +47,6 @@ public partial class AccountTemplate : UserControl
|
||||
this.DataContext.As<LoginCredentials>()!.Username = this.Username;
|
||||
}
|
||||
|
||||
private void CharacterNameTextbox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.DataContext.As<LoginCredentials>()!.CharacterName = this.CharacterName;
|
||||
}
|
||||
|
||||
private void Passwordbox_PasswordChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.Password = sender.As<PasswordBox>()?.Password;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="{Binding Item.Name}"
|
||||
<TextBlock Text="{Binding ElementName=_this, Path=ItemName, Mode=OneWay}"
|
||||
FontSize="16"
|
||||
Grid.Row="0"
|
||||
Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Services.Scanner;
|
||||
using Daybreak.Services.TradeChat;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Core.Extensions;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
@@ -14,22 +17,28 @@ namespace Daybreak.Controls.Templates;
|
||||
/// </summary>
|
||||
public partial class BagItemMenu : UserControl
|
||||
{
|
||||
private readonly IGuildwarsMemoryReader guildwarsMemoryReader;
|
||||
private readonly IItemHashService itemHashService;
|
||||
|
||||
public event EventHandler? CloseClicked;
|
||||
public event EventHandler<ItemBase>? ItemWikiClicked;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string itemName = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private string modHash = string.Empty;
|
||||
|
||||
public BagItemMenu()
|
||||
: this(Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IItemHashService>())
|
||||
: this(Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IGuildwarsMemoryReader>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IItemHashService>())
|
||||
{
|
||||
}
|
||||
|
||||
private BagItemMenu(
|
||||
IGuildwarsMemoryReader guildwarsMemoryReader,
|
||||
IItemHashService itemHashService)
|
||||
{
|
||||
this.guildwarsMemoryReader = guildwarsMemoryReader.ThrowIfNull();
|
||||
this.itemHashService = itemHashService.ThrowIfNull();
|
||||
this.InitializeComponent();
|
||||
}
|
||||
@@ -39,7 +48,7 @@ public partial class BagItemMenu : UserControl
|
||||
this.CloseClicked?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void UserControl_DataContextChanged(object _, DependencyPropertyChangedEventArgs e)
|
||||
private async void UserControl_DataContextChanged(object _, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (this.DataContext is not IBagContent content)
|
||||
{
|
||||
@@ -47,6 +56,16 @@ public partial class BagItemMenu : UserControl
|
||||
}
|
||||
|
||||
this.ModHash = this.itemHashService.ComputeHash(content);
|
||||
var name = await this.guildwarsMemoryReader.GetItemName(
|
||||
content is BagItem bagItem ? bagItem.Item.Id :
|
||||
content is UnknownBagItem unknownBagItem ? (int)unknownBagItem.ItemId :
|
||||
0,
|
||||
content.Modifiers.Select(mod => mod.Modifier).ToList(),
|
||||
CancellationToken.None).ConfigureAwait(true);
|
||||
if (name is not null)
|
||||
{
|
||||
this.ItemName = name;
|
||||
}
|
||||
}
|
||||
|
||||
private void WikiTextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
|
||||
@@ -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>(),
|
||||
|
||||
@@ -33,9 +33,6 @@
|
||||
Foreground="{StaticResource MahApps.Brushes.Accent}"
|
||||
Visibility="{Binding ElementName=_this, Path=GameRunning, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"/>
|
||||
</WrapPanel>
|
||||
<TextBlock Text="{Binding Credentials.CharacterName}"
|
||||
FontSize="16"
|
||||
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"/>
|
||||
<TextBlock Text="{Binding ExecutablePath}"
|
||||
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
|
||||
FontSize="12"
|
||||
@@ -52,9 +49,6 @@
|
||||
FontSize="22"
|
||||
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"/>
|
||||
</WrapPanel>
|
||||
<TextBlock Text="{Binding Credentials.CharacterName}"
|
||||
FontSize="16"
|
||||
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"/>
|
||||
<TextBlock Text="{Binding ExecutablePath}"
|
||||
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
|
||||
FontSize="12"
|
||||
|
||||
@@ -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,24 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Converters;
|
||||
public sealed class DoubleMultiplierConverter : IValueConverter
|
||||
{
|
||||
public double Multiplier { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not double d)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return d * this.Multiplier;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
}
|
||||
+26
-17
@@ -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>net6.0-windows</TargetFramework>
|
||||
<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.128</Version>
|
||||
<Version>0.9.9.6</Version>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
@@ -23,6 +21,10 @@
|
||||
<None Remove="Resources\NotifyClose.wav" />
|
||||
<None Remove="Resources\NotifyError.wav" />
|
||||
<None Remove="Resources\NotifyInformation.wav" />
|
||||
<None Remove="Resources\Snow1.png" />
|
||||
<None Remove="Resources\Snow2.png" />
|
||||
<None Remove="Resources\Snow3.png" />
|
||||
<None Remove="Resources\Snow4.png" />
|
||||
<None Remove="Services\Drawing\Resources\Bag.svg" />
|
||||
<None Remove="Services\Drawing\Resources\CircledStar.svg" />
|
||||
<None Remove="Services\Drawing\Resources\Dungeon.svg" />
|
||||
@@ -41,6 +43,10 @@
|
||||
<EmbeddedResource Include="Resources\NotifyClose.wav" />
|
||||
<EmbeddedResource Include="Resources\NotifyError.wav" />
|
||||
<EmbeddedResource Include="Resources\NotifyInformation.wav" />
|
||||
<EmbeddedResource Include="Resources\Snow1.png" />
|
||||
<EmbeddedResource Include="Resources\Snow2.png" />
|
||||
<EmbeddedResource Include="Resources\Snow3.png" />
|
||||
<EmbeddedResource Include="Resources\Snow4.png" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\Bag.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\CircledStar.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\Dungeon.svg" />
|
||||
@@ -60,7 +66,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
<None Include="..\build\Daybreak.GWCA\$(Configuration)\Daybreak.GWCA.dll" Link="GWCA\Daybreak.GWCA.dll">
|
||||
<None Include="..\Daybreak.GWCA\bin\$(Configuration)\Daybreak.GWCA.dll" Link="GWCA\Daybreak.GWCA.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
@@ -81,31 +87,35 @@
|
||||
|
||||
<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.57" />
|
||||
<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-rc1.2" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc2" />
|
||||
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2088.41" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.75" />
|
||||
<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.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.4" />
|
||||
<PackageReference Include="Svg" Version="3.4.6" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="7.0.2" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="8.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageReference Include="SystemExtensions.NetCore" Version="1.0.1" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.6.2" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard.DependencyInjection" Version="1.3.1" />
|
||||
<PackageReference Include="WpfExtended" Version="0.7.3" />
|
||||
<PackageReference Include="WpfExtended" Version="0.7.7" />
|
||||
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.2" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="2.1.0" />
|
||||
<PackageReference Include="WriteableBitmapEx" Version="1.6.8" />
|
||||
@@ -115,7 +125,6 @@
|
||||
<Folder Include="GWCA\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="echo.>$(Version).version" />
|
||||
</Target>
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
using Daybreak.Models.Progress;
|
||||
using Daybreak.Services.Drawing;
|
||||
using Daybreak.Services.ExceptionHandling;
|
||||
using Daybreak.Services.GWCA;
|
||||
using Daybreak.Services.Injection;
|
||||
using Daybreak.Services.Mods;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Services.Notifications;
|
||||
using Daybreak.Services.Options;
|
||||
using Daybreak.Services.Plugins;
|
||||
using Daybreak.Services.ReShade;
|
||||
using Daybreak.Services.Screens;
|
||||
using Daybreak.Services.Startup;
|
||||
using Daybreak.Services.Themes;
|
||||
@@ -19,14 +16,16 @@ using Microsoft.Extensions.Logging;
|
||||
using Slim;
|
||||
using Slim.Integration.ServiceCollection;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
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>
|
||||
@@ -66,7 +65,7 @@ public sealed class Launcher : ExtendedApplication<MainWindow>
|
||||
return this.exceptionHandler?.HandleException(e) is true;
|
||||
}
|
||||
|
||||
protected override async void ApplicationStarting()
|
||||
protected override void ApplicationStarting()
|
||||
{
|
||||
/*
|
||||
* Show splash screen before beginning to load the rest of the application.
|
||||
|
||||
@@ -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" />
|
||||
@@ -58,7 +58,7 @@
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<Grid Background="Transparent">
|
||||
<Grid Background="Black">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
@@ -72,16 +72,37 @@
|
||||
<effects:ContrastAdjust Brightness="0.01"
|
||||
Contrast="1.3" />
|
||||
</Border.Effect>
|
||||
<Border Effect="{Binding ElementName=_this, Path=BlurBackground, Mode=OneWay, Converter={StaticResource BooleanToEffectConverter}, ConverterParameter={StaticResource BlurEffect}}">
|
||||
<Border Effect="{Binding ElementName=_this, Path=PaintifyBackground, Mode=OneWay, Converter={StaticResource BooleanToEffectConverter}, ConverterParameter={StaticResource PaintifyEffect}}">
|
||||
<controls:ImageViewer x:Name="ImageViewer" />
|
||||
<Grid>
|
||||
<Border Effect="{Binding ElementName=_this, Path=BlurBackground, Mode=OneWay, Converter={StaticResource BooleanToEffectConverter}, ConverterParameter={StaticResource BlurEffect}}">
|
||||
<Border Effect="{Binding ElementName=_this, Path=PaintifyBackground, Mode=OneWay, Converter={StaticResource BooleanToEffectConverter}, ConverterParameter={StaticResource PaintifyEffect}}">
|
||||
<controls:ImageViewer x:Name="ImageViewer" />
|
||||
</Border>
|
||||
</Border>
|
||||
</Border>
|
||||
<controls:SnowfallOverlay
|
||||
Visibility="{Binding ElementName=_this, Path=WintersdayMode, Mode=OneWay, Converter={StaticResource BaseBooleanToVisibilityConverter}}"
|
||||
Opacity="0.4"
|
||||
BaseWind1="0.0247"
|
||||
BaseWind2="0.00427"
|
||||
BaseWind3="0.00443"
|
||||
BaseWind4="0.00405"
|
||||
BaseWind5="0.00362"
|
||||
WindStrength1="0.006"
|
||||
WindStrength2="0.001"
|
||||
WindStrength3="0.00096"
|
||||
WindStrength4="0.00098"
|
||||
WindStrength5="0.0009"
|
||||
FlakeSize1="14"
|
||||
FlakeSize2="6"
|
||||
FlakeSize3="4.6"
|
||||
FlakeSize4="3.2"
|
||||
FlakeSize5="2.1">
|
||||
</controls:SnowfallOverlay>
|
||||
</Grid>
|
||||
</Border>
|
||||
<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"
|
||||
@@ -108,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>
|
||||
@@ -153,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"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Daybreak.Configuration.Options;
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Daybreak.Services.Menu;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Services.Options;
|
||||
@@ -10,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;
|
||||
@@ -33,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 +57,15 @@ public partial class MainWindow : MetroWindow
|
||||
private bool paintifyBackground;
|
||||
[GenerateDependencyProperty]
|
||||
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 &&
|
||||
@@ -125,11 +137,12 @@ public partial class MainWindow : MetroWindow
|
||||
{
|
||||
this.PaintifyBackground = this.themeOptions.Value.BackgroundPaintify;
|
||||
this.BlurBackground = this.themeOptions.Value.BackgroundBlur;
|
||||
this.WintersdayMode = this.themeOptions.Value.WintersdayMode;
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -152,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)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Daybreak.Models;
|
||||
public readonly struct ApplicationLauncherContext
|
||||
{
|
||||
public string ExecutablePath { get; init; }
|
||||
public Process Process { get; init; }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user