Improve Focus View performance and hooking availability (#1009) (Closes #1007)

This commit is contained in:
2025-06-24 13:38:02 +02:00
parent accfed2440
commit 5a92b916dd
7 changed files with 67 additions and 37 deletions
+2 -1
View File
@@ -325,7 +325,8 @@ public sealed class MainPlayerService : IDisposable
gameContext.Pointer->CharContext is null ||
gameContext.Pointer->WorldContext is null ||
gameContext.Pointer->PartyContext is null ||
instanceInfoContext.IsNull)
instanceInfoContext.IsNull ||
instanceInfoContext.Pointer->CurrentMapInfo is null)
{
scopedLogger.LogError("Game context is not initialized");
return new InstanceInfo(0, 0, 0, 0, Shared.Models.Api.InstanceType.Loading, DistrictRegionInfo.Unknown, LanguageInfo.Unknown, CampaignInfo.Unknown, ContinentInfo.Unknown, RegionInfo.Unknown, DifficultyInfo.Unknown);
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
namespace Daybreak.Shared.Services.Api;
public interface IDaybreakApiService : IModService
{
void RequestInstancesAnnouncement();
Task<ScopedApiContext?> AttachDaybreakApiContext(GuildWarsApplicationLaunchContext launchContext, ScopedApiContext scopedApiContext, CancellationToken cancellationToken);
Task<ScopedApiContext?> AttachDaybreakApiContext(GuildWarsApplicationLaunchContext launchContext, CancellationToken cancellationToken);
Task<ScopedApiContext?> FindDaybreakApiContextByCredentials(LoginCredentials loginCredentials, CancellationToken cancellationToken);
@@ -4,7 +4,9 @@ using System.Collections.Generic;
namespace Daybreak.Shared.Services.MDns;
public interface IMDomainRegistrar
{
public IReadOnlyList<Uri>? Resolve(string service);
IReadOnlyList<Uri>? Resolve(string service);
public IReadOnlyList<Uri>? QueryByServiceName(Func<string, bool> query);
IReadOnlyList<Uri>? QueryByServiceName(Func<string, bool> query);
void QueryAllServices();
}
@@ -132,6 +132,11 @@ public sealed class DaybreakApiService(
return default;
}
public void RequestInstancesAnnouncement()
{
this.mDomainRegistrar.QueryAllServices();
}
public Task OnGuildWarsCreated(GuildWarsCreatedContext guildWarsCreatedContext, CancellationToken cancellationToken) =>
Task.Factory.StartNew(() => this.InjectWithStub(guildWarsCreatedContext), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
@@ -67,6 +67,11 @@ public sealed class MDomainRegistrar(
return default;
}
public void QueryAllServices()
{
this.serviceDiscovery.QueryAllServices();
}
private void ServiceDiscovery_ServiceDiscovered(object? _, DomainName e)
{
var labels = e.Labels;
+41 -31
View File
@@ -133,50 +133,30 @@ public partial class FocusView : UserControl
return;
}
if (this.PauseDataFetching)
{
await Task.Delay(MainPlayerDataFrequency, cancellationToken);
continue;
}
if (this.DataContext is not FocusViewContext context)
{
await Task.Delay(MainPlayerDataFrequency, cancellationToken);
continue;
}
if (context.LaunchContext.GuildWarsProcess?.HasExited is not false)
if (context.LaunchContext.GuildWarsProcess.HasExited)
{
this.logger.LogInformation($"Executable is not running. Returning to {nameof(LauncherView)}");
this.viewManager.ShowView<LauncherView>();
this.cancellationTokenSource?.Cancel();
return;
}
if (this.PauseDataFetching)
{
await Task.Delay(MainPlayerDataFrequency, cancellationToken);
continue;
}
var isAvailableTask = context.ApiContext.IsAvailable(cancellationToken);
var mainPlayerInfoTask = context.ApiContext.GetMainPlayerInfo(cancellationToken);
var mainPlayerStateTask = context.ApiContext.GetMainPlayerState(cancellationToken);
var instanceInfoTask = context.ApiContext.GetMainPlayerInstanceInfo(cancellationToken);
var characterSelectTask = context.ApiContext.GetCharacters(cancellationToken);
var titleInfoTask = context.ApiContext.GetTitleInfo(cancellationToken);
var questLogTask = context.ApiContext.GetMainPlayerQuestLog(cancellationToken);
await Task.WhenAll(
isAvailableTask,
mainPlayerInfoTask,
mainPlayerStateTask,
instanceInfoTask,
characterSelectTask,
titleInfoTask,
questLogTask,
Task.Delay(MainPlayerDataFrequency, cancellationToken)).ConfigureAwait(true);
await Task.WhenAny(isAvailableTask, instanceInfoTask);
var isAvailable = await isAvailableTask;
var mainPlayerInfo = await mainPlayerInfoTask;
var mainPlayerState = await mainPlayerStateTask;
var instanceInfo = await instanceInfoTask;
var characters = await characterSelectTask;
var titleInfo = await titleInfoTask;
var questLog = await questLogTask;
if (isAvailable is not true)
{
retries++;
@@ -184,20 +164,50 @@ public partial class FocusView : UserControl
{
scopedLogger.LogError("Could not ensure connection is initialized. Returning to launcher view");
this.notificationService.NotifyError(
title: "GuildWars unresponsive",
title: "Guild Wars unresponsive",
description: "Could not connect to Guild Wars instance. Returning to Launcher view");
this.viewManager.ShowView<LauncherView>();
break;
}
else
{
scopedLogger.LogError("Could not ensure connection is initialized. Backing off before retrying");
await Task.Delay(UninitializedBackoff, cancellationToken);
}
continue;
}
var instanceInfo = await instanceInfoTask;
if (instanceInfo is null ||
instanceInfo.Type is Shared.Models.Api.InstanceType.Loading or Shared.Models.Api.InstanceType.Undefined ||
mainPlayerInfo is null ||
instanceInfo.Type is Shared.Models.Api.InstanceType.Loading or Shared.Models.Api.InstanceType.Undefined)
{
this.MainPlayerDataValid = false;
await Task.Delay(MainPlayerDataFrequency, cancellationToken);
continue;
}
var mainPlayerInfoTask = context.ApiContext.GetMainPlayerInfo(cancellationToken);
var mainPlayerStateTask = context.ApiContext.GetMainPlayerState(cancellationToken);
var characterSelectTask = context.ApiContext.GetCharacters(cancellationToken);
var titleInfoTask = context.ApiContext.GetTitleInfo(cancellationToken);
var questLogTask = context.ApiContext.GetMainPlayerQuestLog(cancellationToken);
await Task.WhenAll(
mainPlayerInfoTask,
mainPlayerStateTask,
characterSelectTask,
titleInfoTask,
questLogTask,
Task.Delay(MainPlayerDataFrequency, cancellationToken)).ConfigureAwait(true);
var mainPlayerInfo = await mainPlayerInfoTask;
var mainPlayerState = await mainPlayerStateTask;
var characters = await characterSelectTask;
var titleInfo = await titleInfoTask;
var questLog = await questLogTask;
if (mainPlayerInfo is null ||
mainPlayerState is null ||
characters is null ||
questLog is null)
+9 -3
View File
@@ -262,6 +262,8 @@ public partial class LauncherView : UserControl
launcherViewContext.CanLaunch = false;
launcherViewContext.CanAttach = false;
launcherViewContext.CanKill = false;
launcherViewContext.AppContext = default;
launcherViewContext.ApiContext = default;
return;
}
@@ -271,6 +273,8 @@ public partial class LauncherView : UserControl
launcherViewContext.CanLaunch = true;
launcherViewContext.CanAttach = false;
launcherViewContext.CanKill = false;
launcherViewContext.AppContext = default;
launcherViewContext.ApiContext = default;
return;
}
@@ -433,7 +437,8 @@ public partial class LauncherView : UserControl
var launchNotificationToken = this.notificationService.NotifyInformation(
title: "Launching Guild Wars...",
description: $"Attempting to launch Guild Wars process at {launcherViewContext.Configuration.ExecutablePath}");
description: $"Attempting to launch Guild Wars process at {launcherViewContext.Configuration.ExecutablePath}",
expirationTime: DateTime.MaxValue);
var launchedContext = await this.applicationLauncher.LaunchGuildwars(launcherViewContext.Configuration, cancellationToken);
if (launchedContext is null)
{
@@ -445,6 +450,7 @@ public partial class LauncherView : UserControl
}
launchNotificationToken.Cancel();
this.daybreakApiService.RequestInstancesAnnouncement();
this.launchConfigurationService.SetLastLaunchConfigurationWithCredentials(launcherViewContext.Configuration);
if (!this.focusViewOptions.Value.Enabled)
{
@@ -455,8 +461,8 @@ public partial class LauncherView : UserControl
title: "Attaching to Guild Wars process...",
description: "Attempting to attach to Guild Wars process");
//Wait 2 seconds to allow the launched Guild Wars process to advertise itself
await Task.Delay(2000, cancellationToken);
//Wait 1 second to allow the launched Guild Wars process to advertise itself
await Task.Delay(1000, cancellationToken);
var apiContext = await this.daybreakApiService.AttachDaybreakApiContext(launchedContext, cancellationToken);
attachNotificationToken.Cancel();