Skip to content
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
440 changes: 291 additions & 149 deletions Daybreak.API/Interop/GWCA.cs

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Daybreak.Core/Daybreak.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@
</Target>

<ItemGroup>
<PackageReference Include="Elastic.OpenTelemetry" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Icons" />
<PackageReference Include="Microsoft.AspNetCore.Components" />
<PackageReference Include="Microsoft.Identity.Client" />
<PackageReference Include="OpenTelemetry.Exporter.Console" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
<PackageReference Include="PeNet" />
<PackageReference Include="Plumsy" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,15 +310,19 @@ CancellationToken cancellationToken
{
var scopedLogger = this.logger.CreateScopedLogger(flowIdentifier: destinationPath);
var exePath = Path.Combine(destinationPath, ExeName);
scopedLogger.LogDebug("Fetching latest Guild Wars executable");
var latestGwPath = await this.FetchLatestGuildwarsInternal(progress, cancellationToken);
if (latestGwPath is null)
{
scopedLogger.LogError("Failed to fetch latest Guild Wars executable");
progress.Report(ProgressFailed);
return false;
}

scopedLogger.LogDebug("Copying latest Guild Wars executable to destination");
var filePath = Path.GetFullPath(exePath);
File.Copy(latestGwPath, filePath, true);
scopedLogger.LogDebug("Copied latest Guild Wars executable to destination");
progress.Report(ProgressStartingExecutable);
await Task.Delay(100, cancellationToken);
this.guildWarsExecutableManager.AddExecutable(filePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
using PeNet.Header.Pe;

namespace Daybreak.Services.Guildwars.Utils;
/// <summary>
/// https://github.com/gwdevhub/gwlauncher/blob/master/GW%20Launcher/Guildwars/FileIdFinder.cs
/// </summary>

internal sealed class GuildWarsExecutableParser
{
// Used by older Guild Wars versions
private readonly static byte[] VersionPattern = [0x8B, 0xC8, 0x33, 0xDB, 0x39, 0x8D, 0xC0, 0xFD, 0xFF, 0xFF, 0x0F, 0x95, 0xC3];

// Used by newer Guild Wars versions
private readonly static byte?[] FileIdFunctionPattern = [0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x08, 0xE8, null, null, null, null, 0x83, 0x3D, null, null, null, null, 0x00];
// Used by newer Guild Wars versions. Matches ProcessVersionUpdate prologue:
// push ebp; mov ebp,esp; sub esp,N; call <addr>; cmp dword ptr [global], 0
// Byte 5 (stack size) is wildcarded since it changes across builds.
private readonly static byte?[] FileIdFunctionPattern = [0x55, 0x8B, 0xEC, 0x83, 0xEC, null, 0xE8, null, null, null, null, 0x83, 0x3D, null, null, null, null, 0x00];

private readonly PeFile peFile;
private readonly ImageSectionHeader textSection;
Expand All @@ -38,13 +38,39 @@ public Task<int> GetFileId(CancellationToken cancellationToken)
return Task.Run(() =>
{
var patternRva = this.FindWithWildcards(FileIdFunctionPattern);
var callRva = patternRva + 0x32;
var fileIdFunctionRva = this.FollowCall(callRva);
var fileIdFunctionRva = this.FindGetFileIdCall(patternRva);
var fileId = (int)this.Read(fileIdFunctionRva + 1);
return fileId;
}, cancellationToken);
}

// GetFileId is a tiny function: mov eax, <imm32>; ret (bytes: B8 xx xx xx xx C3).
// Scan E8 (call) instructions within the matched function and follow each one
// to find the call whose target matches that shape.
private uint FindGetFileIdCall(uint functionRva, int scanLength = 0x80)
{
for (int offset = 0; offset < scanLength; offset++)
{
var rva = functionRva + (uint)offset;
var posInFile = this.RvaToOffset(rva);
if (this.peFile.RawFile.ReadByte(posInFile) != 0xE8)
{
continue;
}

var targetRva = rva + (uint)BitConverter.ToInt32(this.peFile.RawFile.ToArray(), posInFile + 1) + 5;
var targetOffset = this.RvaToOffset(targetRva);
// Check for: B8 xx xx xx xx C3 (mov eax, imm32; ret)
if (this.peFile.RawFile.ReadByte(targetOffset) == 0xB8 &&
this.peFile.RawFile.ReadByte(targetOffset + 5) == 0xC3)
{
return targetRva;
}
}

throw new Exception("Couldn't find GetFileId call within the function");
}

private uint FindWithWildcards(byte?[] pattern, int offset = 0)
{
var buffer = this.peFile.RawFile.AsSpan((int)this.textSection.PointerToRawData, (int)this.textSection.SizeOfRawData);
Expand Down
8 changes: 3 additions & 5 deletions Daybreak.Core/Services/Screenshots/ScreenshotService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ private static (Color Color, bool IsDark) GetDominantColor(Image<Rgba32> image)

image.ProcessPixelRows(accessor =>
{
Span<int> rValues = stackalloc int[Vector<int>.Count];
Span<int> gValues = stackalloc int[Vector<int>.Count];
Span<int> bValues = stackalloc int[Vector<int>.Count];
for (int y = 0; y < accessor.Height; y += SampleQuality)
{
var rowSpan = accessor.GetRowSpan(y);
Expand All @@ -108,11 +111,6 @@ private static (Color Color, bool IsDark) GetDominantColor(Image<Rgba32> image)
var sumB = Vector<long>.Zero;
int simdPixelCount = 0;

// Gather sampled pixels into arrays for vectorization
Span<int> rValues = stackalloc int[Vector<int>.Count];
Span<int> gValues = stackalloc int[Vector<int>.Count];
Span<int> bValues = stackalloc int[Vector<int>.Count];

// Collect sampled pixels for SIMD processing
while (x + (Vector<int>.Count * SampleQuality) <= rowSpan.Length)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ ILogger<VerifyNativeComponentsAction> logger
private const string ApiFolder = "Api";
private const string InstallerFolder = "Installer";

private static readonly string[] InjectorFiles = OperatingSystem.IsWindows()
? ["Daybreak.Injector.exe", "FASM.DLL"]
: ["Daybreak.Injector.exe", "FASM.DLL"];
private static readonly string[] InjectorFiles = ["Daybreak.Injector.exe"];
private static readonly string[] ApiFiles = ["Daybreak.API.dll"];
private static readonly string[] InstallerFiles = OperatingSystem.IsWindows()
? ["Daybreak.Installer.exe"]
Expand Down
58 changes: 1 addition & 57 deletions Dependencies/GWCA/Include/GWCA/Constants/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ namespace GW {
MargridTheSly, Zenmai, Olias, Razah, MOX, KeiranThackeray, Jora,
PyreFierceshot, Anton, Livia, Hayda, Kahmu, Gwen, Xandra, Vekk,
Ogden, Merc1, Merc2, Merc3, Merc4, Merc5, Merc6, Merc7, Merc8,
Miku, ZeiRi, Devona, GhostofAlthea, Count
Miku, ZeiRi, Devona, GhostOfAlthea, Count
};

enum class MaterialSlot : uint32_t {
Expand All @@ -159,49 +159,6 @@ namespace GW {
Count
};

constexpr std::array HeroProfs = {
Profession::None,
Profession::Mesmer, // Norgu
Profession::Warrior,// Goren
Profession::Monk, // Tahlkora
Profession::Necromancer, // Master Of Whispers
Profession::Ranger, // Acolyte Jin
Profession::Warrior, // Koss
Profession::Monk, // Dunkoro
Profession::Elementalist, // Acolyte Sousuke
Profession::Dervish, // Melonni
Profession::Elementalist, // Zhed Shadowhoof
Profession::Paragon, // General Morgahn
Profession::Ranger, // Magrid The Sly
Profession::Assassin, // Zenmai
Profession::Necromancer, // Olias
Profession::None, // Razah
Profession::Dervish, // MOX
Profession::Paragon, // Keiran Thackeray
Profession::Warrior, // Jora
Profession::Ranger, // Pyre Fierceshot
Profession::Assassin, // Anton
Profession::Necromancer, // Livia
Profession::Paragon, // Hayda
Profession::Dervish, // Kahmu
Profession::Mesmer, // Gwen
Profession::Ritualist, // Xandra
Profession::Elementalist, // Vekk
Profession::Monk, // Ogden
Profession::None, // Mercenary Hero 1
Profession::None, // Mercenary Hero 2
Profession::None, // Mercenary Hero 3
Profession::None, // Mercenary Hero 4
Profession::None, // Mercenary Hero 5
Profession::None, // Mercenary Hero 6
Profession::None, // Mercenary Hero 7
Profession::None, // Mercenary Hero 8
Profession::Assassin, // Miku
Profession::Ritualist, // Zei Ri
Profession::Warrior, // Devona
Profession::Mesmer // Ghost of Althea
};

enum class TitleID : uint32_t {
Hero, TyrianCarto, CanthanCarto, Gladiator, Champion, Kurzick,
Luxon, Drunkard,
Expand All @@ -224,12 +181,6 @@ namespace GW {
enum class Tick { NOT_READY, READY };

enum class InterfaceSize { SMALL = -1, NORMAL, LARGE, LARGER };
namespace HealthbarHeight {
constexpr size_t Small = 24;
constexpr size_t Normal = 22;
constexpr size_t Large = 26;
constexpr size_t Larger = 30;
}

// travel, region, districts
enum class ServerRegion {
Expand Down Expand Up @@ -350,12 +301,5 @@ namespace GW {
ritualist_symbol = 35,
dervish_symbol = 36,
};

namespace Camera {
constexpr float FIRST_PERSON_DIST = 2.f;
constexpr float DEFAULT_DIST = 750.f;
}

constexpr size_t SkillMax = 0xd69;
}
}
12 changes: 10 additions & 2 deletions Dependencies/GWCA/Include/GWCA/Constants/Maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,9 +794,9 @@ namespace GW {
MISSION_CINEMATIC_MISSION_PACK_GWX_INTRODUCTION,
Piken_Square_pre_Searing_outpost,

// Map 780 has invalid continent, name and description
Forsaken_Tunnels_Presearing_Level1,

Secret_Lair_of_the_Snowmen2 = 781, // ?
Secret_Lair_of_the_Snowmen2, // ?
Secret_Lair_of_the_Snowmen3, // ?
Droknars_Forge_cinematic, // ?
Isle_of_the_Nameless_PvP,
Expand Down Expand Up @@ -892,6 +892,14 @@ namespace GW {
Lakeside_County_1070_AE,
Ashford_Catacombs_1070_AE,

Forsaken_Tunnels_Presearing_Level2,
Forsaken_Tunnels_Presearing_Level3,

Forsaken_Tunnels_Level1,
Forsaken_Tunnels_Level2,
Forsaken_Tunnels_Level3,
Forsaken_Tunnels_Level4,

Count = 0x373,
};
}
Expand Down
Loading
Loading