Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Name module improvements #431

Merged
merged 1 commit into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 33 additions & 13 deletions Daybreak.GWCA/source/NameModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <limits>

namespace Daybreak::Modules::NameModule {
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;
Expand All @@ -32,28 +33,25 @@ namespace Daybreak::Modules::NameModule {
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() {
Expand All @@ -62,18 +60,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 = WStringToString(*name);
delete(name);
promise->set_value(payload);
}
});

initialized = true;
Expand Down
1 change: 0 additions & 1 deletion Daybreak/Configuration/ProjectConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ public override void RegisterServices(IServiceCollection services)
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>();
Expand Down
4 changes: 2 additions & 2 deletions Daybreak/Controls/LivingEntityContextMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -64,7 +64,7 @@ private async void LivingEntityContextMenu_DataContextChanged(object sender, Sys

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)
Expand Down
50 changes: 27 additions & 23 deletions Daybreak/Controls/Minimap/GuildwarsMinimap.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
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;
Expand Down Expand Up @@ -46,7 +45,6 @@ public partial class GuildwarsMinimap : UserControl
private readonly List<Position> mainPlayerPositionHistory = new();
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);
Expand All @@ -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]
Expand All @@ -91,12 +88,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>())
{
Expand All @@ -105,13 +102,11 @@ public GuildwarsMinimap()
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);

Expand All @@ -135,7 +130,6 @@ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
}
else if (e.Property == PathingDataProperty)
{
this.guildwarsEntityDebouncer.ClearCaches();
this.mainPlayerPositionHistory.Clear();
this.lastPathfindingPoint = new Point(0, 0);
this.pathfindingObjectiveCount = 0;
Expand All @@ -161,12 +155,11 @@ private void UpdateGameData()
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;
}
Expand All @@ -175,7 +168,7 @@ private void UpdateGameData()
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!.Value;
this.originPoint = new Point(
position.X - (screenVirtualWidth / 2) - (this.originOffset.X / this.Zoom),
position.Y + (screenVirtualHeight / 2) + (this.originOffset.Y / this.Zoom));
Expand All @@ -189,19 +182,18 @@ private void UpdateGameData()
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;
Expand Down Expand Up @@ -320,12 +312,12 @@ private void DrawEntities()
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.DrawEntities(bitmap, this.GameData, this.TargetEntityId);
bitmap.Unlock();
this.drawingLatency.Record(sw.ElapsedMilliseconds);
}
Expand Down Expand Up @@ -387,8 +379,8 @@ private async void CalculatePathsToObjectives()

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,
};

/*
Expand Down Expand Up @@ -689,24 +681,36 @@ private void QuestContextMenu_QuestContextMenuClicked(object _, QuestMetadata? q
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;
}

this.PlayerInformationClicked?.Invoke(this, playerInformation);
if (tuple.Player is null)
{
return;
}

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)
Expand Down
4 changes: 2 additions & 2 deletions Daybreak/Controls/PlayerContextMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -49,6 +49,6 @@ private async void PlayerContextMenu_DataContextChanged(object sender, System.Wi

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));
}
}
2 changes: 1 addition & 1 deletion Daybreak/Daybreak.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9.8.128</Version>
<Version>0.9.8.129</Version>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
Expand Down
11 changes: 0 additions & 11 deletions Daybreak/Models/Guildwars/DebounceResponse.cs

This file was deleted.

40 changes: 20 additions & 20 deletions Daybreak/Services/Drawing/DrawingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,26 @@ public bool IsEntityOnScreen(Position? position, out int x, out int y)
return true;
}

public void DrawEntities(WriteableBitmap bitmap, DebounceResponse debounceResponse, int targetEntityId)
public void DrawEntities(WriteableBitmap bitmap, GameData gameData, int targetEntityId)
{
if (bitmap is null)
{
return;
}

if (debounceResponse is null ||
debounceResponse.MainPlayer.Position is null ||
debounceResponse.WorldPlayers is null |
debounceResponse.Party is null ||
debounceResponse.LivingEntities is null)
if (gameData is null ||
gameData.MainPlayer?.Position is null ||
gameData.WorldPlayers is null |
gameData.Party is null ||
gameData.LivingEntities is null)
{
return;
}

var entities = debounceResponse.LivingEntities.OfType<IEntity>()
.Concat(debounceResponse.Party!.OfType<IEntity>())
.Concat(debounceResponse.WorldPlayers!.OfType<IEntity>())
.Append(debounceResponse.MainPlayer)
var entities = gameData.LivingEntities.OfType<IEntity>()
.Concat(gameData.Party!.OfType<IEntity>())
.Concat(gameData.WorldPlayers!.OfType<IEntity>())
.Append(gameData.MainPlayer)
.Where(IsValidPositionalEntity);

var nonTargetedEntities = entities.Where(e => e.Id != targetEntityId);
Expand Down Expand Up @@ -266,26 +266,26 @@ public void DrawQuestObjectives(WriteableBitmap bitmap, IEnumerable<QuestMetadat
}
}

public void DrawEngagementArea(WriteableBitmap bitmap, DebounceResponse debounceResponse)
public void DrawEngagementArea(WriteableBitmap bitmap, GameData gameData)
{
if (bitmap is null)
{
return;
}

if (debounceResponse is null ||
debounceResponse.MainPlayer.Position is null ||
debounceResponse.WorldPlayers is null |
debounceResponse.Party is null ||
debounceResponse.LivingEntities is null)
if (gameData is null ||
gameData.MainPlayer?.Position is null ||
gameData.WorldPlayers is null |
gameData.Party is null ||
gameData.LivingEntities is null)
{
return;
}

var entities = debounceResponse.LivingEntities.OfType<IEntity>()
.Concat(debounceResponse.Party!.OfType<IEntity>())
.Concat(debounceResponse.WorldPlayers!.OfType<IEntity>())
.Append(debounceResponse.MainPlayer)
var entities = gameData.LivingEntities.OfType<IEntity>()
.Concat(gameData.Party!.OfType<IEntity>())
.Concat(gameData.WorldPlayers!.OfType<IEntity>())
.Append(gameData.MainPlayer)
.Where(IsValidPositionalEntity);

foreach (var entity in entities)
Expand Down
Loading
Loading