diff --git a/Daybreak.API/Interop/GuildWars/PreGameContext.cs b/Daybreak.API/Interop/GuildWars/PreGameContext.cs index d429a9c0..29500d90 100644 --- a/Daybreak.API/Interop/GuildWars/PreGameContext.cs +++ b/Daybreak.API/Interop/GuildWars/PreGameContext.cs @@ -12,13 +12,7 @@ public readonly struct PreGameContext [FieldOffset(0x0124)] public readonly uint ChosenCharacterIndex; - [FieldOffset(0x0140)] - public readonly uint Index1; - - [FieldOffset(0x0144)] - public readonly uint Index2; - - [FieldOffset(0x00148)] + [FieldOffset(0x0148)] public readonly GuildWarsArray LoginCharacters; } diff --git a/Daybreak.API/Interop/GuildWars/Preferences.cs b/Daybreak.API/Interop/GuildWars/Preferences.cs new file mode 100644 index 00000000..a18e31b8 --- /dev/null +++ b/Daybreak.API/Interop/GuildWars/Preferences.cs @@ -0,0 +1,40 @@ +namespace Daybreak.API.Interop.GuildWars; + +public enum EnumPreference : uint +{ + CharSortOrder = 0, + AntiAliasing = 1, + Reflections = 2, + ShaderQuality = 3, + ShadowQuality = 4, + TerrainQuality = 5, + InterfaceSize = 6, + FrameLimiter = 7, + Count = 8 +} + +public enum CharSortOrder : uint +{ + None = 0, + Alphabetize = 1, + PvPRP = 2 +} + +public enum NumberPreference : uint +{ + AutoTournPartySort = 0, + ChatState = 1, + Count = 0x2b +} + +public enum FlagPreference : uint +{ +} + +public enum StringPreference : uint +{ + Unk1 = 0, + Unk2 = 1, + LastCharacterName = 2, + Count = 3 +} diff --git a/Daybreak.API/Models/UIMessage.cs b/Daybreak.API/Models/UIMessage.cs index eec9eba3..91af3398 100644 --- a/Daybreak.API/Models/UIMessage.cs +++ b/Daybreak.API/Models/UIMessage.cs @@ -10,7 +10,7 @@ public enum UIMessage : uint MouseClick = 0x24, // wparam = UIPacket::kMouseClick* MouseClick2 = 0x31, // wparam = UIPacket::kMouseAction* MouseAction = 0x32, // wparam = UIPacket::kMouseAction* - FrameMessage_QuerySelectedIndex = 0x58, // Used to query selected index in character selector + FrameMessage_QuerySelectedIndex = 0x59, // Used to query selected index in character selector WriteToChatLog = 0x10000000 | 0x7F, // wparam = UIPacket::kWriteToChatLog*. Triggered by the game when it wants to add a new message to chat. WriteToChatLogWithSender = 0x10000000 | 0x80, // wparam = UIPacket::kWriteToChatLogWithSender*. Triggered by the game when it wants to add a new message to chat. CheckUIState = 0x10000000 | 0x118, // lparam = uint32_t* out state (2 = char select ready) diff --git a/Daybreak.API/NativeMethods.cs b/Daybreak.API/NativeMethods.cs index 32f34738..45b6da61 100644 --- a/Daybreak.API/NativeMethods.cs +++ b/Daybreak.API/NativeMethods.cs @@ -11,6 +11,7 @@ internal unsafe static partial class NativeMethods public const int WM_KEYDOWN = 0x0100; public const int WM_KEYUP = 0x0101; public const int WM_CHAR = 0x0102; + public const int VK_LEFT = 0x25; public const int VK_RIGHT = 0x27; public const uint MEM_COMMIT = 0x1000; @@ -36,7 +37,7 @@ internal unsafe static partial class NativeMethods public static partial bool SetConsoleMode(nint hConsoleHandle, uint dwMode); [LibraryImport("user32.dll")] - public static partial nint SendMessageW(nint hWnd, int Msg, nint wParam, nint lParam); + public static partial nint SendMessageW(nint hWnd, int Msg, nint wParam, nuint lParam); [LibraryImport("kernel32.dll", SetLastError = true)] public static partial nint VirtualAlloc( diff --git a/Daybreak.API/Services/CharacterSelectService.cs b/Daybreak.API/Services/CharacterSelectService.cs index 2ad1105f..16a73a44 100644 --- a/Daybreak.API/Services/CharacterSelectService.cs +++ b/Daybreak.API/Services/CharacterSelectService.cs @@ -15,6 +15,7 @@ public sealed class CharacterSelectService( UIContextService uiContextService, GameThreadService gameThreadService, GameContextService gameContextService, + PreferencesService preferencesService, ILogger logger) { [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -29,6 +30,7 @@ public sealed class CharacterSelectService( private readonly UIContextService uiContextService = uiContextService.ThrowIfNull(); private readonly GameThreadService gameThreadService = gameThreadService.ThrowIfNull(); private readonly GameContextService gameContextService = gameContextService.ThrowIfNull(); + private readonly PreferencesService preferencesService = preferencesService.ThrowIfNull(); private readonly ILogger logger = logger.ThrowIfNull(); public Task GetCharacterSelectInformation(CancellationToken cancellationToken) @@ -137,7 +139,6 @@ public sealed class CharacterSelectService( private async Task SelectCharacterToPlay(string characterName, bool play, CancellationToken cancellationToken) { var scopedLogger = this.logger.CreateScopedLogger(); - return await this.gameThreadService.QueueOnGameThread(() => { unsafe @@ -254,8 +255,25 @@ public sealed class CharacterSelectService( return false; } - scopedLogger.LogInformation("Character select ready, selecting {name}", characterName); - return await this.SelectCharacterToPlay(characterName, play: true, cancellationToken); + var previousOrderPreference = await this.gameThreadService.QueueOnGameThread(() => this.preferencesService.GetEnumPreference(EnumPreference.CharSortOrder), cancellationToken); + if (previousOrderPreference is null) + { + scopedLogger.LogError("Failed to get previous character sort order preference"); + return false; + } + + scopedLogger.LogInformation("Previous character sort order preference: {order}. Setting order to alphabetize", (CharSortOrder)previousOrderPreference); + await this.gameThreadService.QueueOnGameThread(() => this.preferencesService.SetEnumPreference(EnumPreference.CharSortOrder, (uint)CharSortOrder.Alphabetize), cancellationToken); + try + { + return await this.SelectCharacterToPlay(characterName, play: true, cancellationToken); + } + finally + { + // TODO: Delay to ensure character select has fully processed the selection before reverting sort order. Should be done after loading into the map. + await Task.Delay(1000, cancellationToken); + await this.gameThreadService.QueueOnGameThread(() => this.preferencesService.SetEnumPreference(EnumPreference.CharSortOrder, previousOrderPreference.Value), cancellationToken); + } } private async Task GetCharNameByUuid(string uuid, CancellationToken cancellationToken) @@ -303,7 +321,7 @@ public sealed class CharacterSelectService( var logoutMessage = new LogOutMessage(0, 1); // Changed to 1 for character select unsafe { - this.uiContextService.SendMessage(Models.UIMessage.Logout, (uint)&logoutMessage, 0); + this.uiContextService.SendMessage(UIMessage.Logout, (uint)&logoutMessage, 0); } }, cancellationToken); } diff --git a/Daybreak.API/Services/Interop/GameContextService.cs b/Daybreak.API/Services/Interop/GameContextService.cs index c14804ea..1a7adcb3 100644 --- a/Daybreak.API/Services/Interop/GameContextService.cs +++ b/Daybreak.API/Services/Interop/GameContextService.cs @@ -177,9 +177,9 @@ public unsafe sealed class GameContextService : IAddressHealthService return 0U; } - preGameContextAddress = *(nuint*)preGameContextAddress; - scopedLogger.LogInformation("Pre-game context address: 0x{address:X8}", preGameContextAddress); - return preGameContextAddress; + var actualAddress = *(nuint*)preGameContextAddress; + scopedLogger.LogInformation("Pre-game context address: 0x{address:X8}", actualAddress); + return actualAddress; } private unsafe nuint GetAvailableCharactersAddress() diff --git a/Daybreak.API/Services/Interop/PreferencesService.cs b/Daybreak.API/Services/Interop/PreferencesService.cs new file mode 100644 index 00000000..3eb4ac35 --- /dev/null +++ b/Daybreak.API/Services/Interop/PreferencesService.cs @@ -0,0 +1,441 @@ +using Daybreak.API.Interop; +using Daybreak.API.Interop.GuildWars; +using Daybreak.API.Models; +using System.Core.Extensions; +using System.Extensions.Core; +using System.Runtime.InteropServices; + +namespace Daybreak.API.Services.Interop; + +public sealed class PreferencesService + : IAddressHealthService +{ + private readonly MemoryScanningService memoryScanningService; + private readonly ILogger logger; + + private readonly GWAddressCache preferencesInitializedAddress; + private readonly GWAddressCache getEnumPreferenceAddress; + private readonly GWAddressCache setEnumPreferenceAddress; + private readonly GWAddressCache getNumberPreferenceAddress; + private readonly GWAddressCache setNumberPreferenceAddress; + private readonly GWAddressCache getFlagPreferenceAddress; + private readonly GWAddressCache setFlagPreferenceAddress; + private readonly GWAddressCache getStringPreferenceAddress; + private readonly GWAddressCache setStringPreferenceAddress; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate uint GetEnumPreferenceDelegate(uint prefId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void SetEnumPreferenceDelegate(uint prefId, uint value); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate uint GetNumberPreferenceDelegate(uint prefId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void SetNumberPreferenceDelegate(uint prefId, uint value); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool GetFlagPreferenceDelegate(uint prefId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void SetFlagPreferenceDelegate(uint prefId, [MarshalAs(UnmanagedType.I1)] bool value); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate nint GetStringPreferenceDelegate(uint prefId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void SetStringPreferenceDelegate(uint prefId, nint value); + + public PreferencesService( + MemoryScanningService memoryScanningService, + ILogger logger) + { + this.logger = logger.ThrowIfNull(); + this.memoryScanningService = memoryScanningService.ThrowIfNull(); + + this.preferencesInitializedAddress = new GWAddressCache(this.GetPreferencesInitializedAddress); + this.getEnumPreferenceAddress = new GWAddressCache(this.GetGetEnumPreferenceAddress); + this.setEnumPreferenceAddress = new GWAddressCache(this.GetSetEnumPreferenceAddress); + this.getNumberPreferenceAddress = new GWAddressCache(this.GetGetNumberPreferenceAddress); + this.setNumberPreferenceAddress = new GWAddressCache(this.GetSetNumberPreferenceAddress); + this.getFlagPreferenceAddress = new GWAddressCache(this.GetGetFlagPreferenceAddress); + this.setFlagPreferenceAddress = new GWAddressCache(this.GetSetFlagPreferenceAddress); + this.getStringPreferenceAddress = new GWAddressCache(this.GetGetStringPreferenceAddress); + this.setStringPreferenceAddress = new GWAddressCache(this.GetSetStringPreferenceAddress); + } + + public List GetAddressStates() + { + return + [ + new AddressState { Address = this.preferencesInitializedAddress.GetAddress() ?? 0, Name = nameof(this.preferencesInitializedAddress) }, + new AddressState { Address = this.getEnumPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.getEnumPreferenceAddress) }, + new AddressState { Address = this.setEnumPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.setEnumPreferenceAddress) }, + new AddressState { Address = this.getNumberPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.getNumberPreferenceAddress) }, + new AddressState { Address = this.setNumberPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.setNumberPreferenceAddress) }, + new AddressState { Address = this.getFlagPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.getFlagPreferenceAddress) }, + new AddressState { Address = this.setFlagPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.setFlagPreferenceAddress) }, + new AddressState { Address = this.getStringPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.getStringPreferenceAddress) }, + new AddressState { Address = this.setStringPreferenceAddress.GetAddress() ?? 0, Name = nameof(this.setStringPreferenceAddress) }, + ]; + } + + public unsafe bool PreferencesInitialized() + { + var addr = this.preferencesInitializedAddress.GetAddress(); + return addr is not null && addr != 0 && *(byte*)addr != 0; + } + + public uint? GetEnumPreference(EnumPreference pref) + { + if (!this.PreferencesInitialized()) + { + return null; + } + + var funcAddr = this.getEnumPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return null; + } + + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + return func((uint)pref); + } + + public bool SetEnumPreference(EnumPreference pref, uint value) + { + if (!this.PreferencesInitialized()) + { + return false; + } + + var funcAddr = this.setEnumPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return false; + } + + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + func((uint)pref, value); + return true; + } + + public uint? GetNumberPreference(NumberPreference pref) + { + if (!this.PreferencesInitialized()) + { + return null; + } + + var funcAddr = this.getNumberPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return null; + } + + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + return func((uint)pref); + } + + public bool SetNumberPreference(NumberPreference pref, uint value) + { + if (!this.PreferencesInitialized()) + { + return false; + } + + var funcAddr = this.setNumberPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return false; + } + + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + func((uint)pref, value); + return true; + } + + public bool? GetFlagPreference(FlagPreference pref) + { + if (!this.PreferencesInitialized()) + { + return null; + } + + var funcAddr = this.getFlagPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return null; + } + + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + return func((uint)pref); + } + + public bool SetFlagPreference(FlagPreference pref, bool value) + { + if (!this.PreferencesInitialized()) + { + return false; + } + + var funcAddr = this.setFlagPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return false; + } + + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + func((uint)pref, value); + return true; + } + + public unsafe string? GetStringPreference(StringPreference pref) + { + if (!this.PreferencesInitialized()) + { + return null; + } + + var funcAddr = this.getStringPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return null; + } + + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + var ptr = func((uint)pref); + if (ptr == 0) + { + return null; + } + + return Marshal.PtrToStringUni(ptr); + } + + public bool SetStringPreference(StringPreference pref, string value) + { + if (!this.PreferencesInitialized()) + { + return false; + } + + var funcAddr = this.setStringPreferenceAddress.GetAddress(); + if (funcAddr is null or 0) + { + return false; + } + + var strPtr = Marshal.StringToHGlobalUni(value); + try + { + var func = Marshal.GetDelegateForFunctionPointer((nint)funcAddr); + func((uint)pref, strPtr); + return true; + } + finally + { + Marshal.FreeHGlobal(strPtr); + } + } + + private nuint GetPreferencesInitializedAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + + // GWCA: FindAssertion("\\Code\\Gw\\Pref\\PrApi.cpp", "location < arrsize(s_flushDelay)", 0, -0x12) + var address = this.memoryScanningService.FindAssertion( + @"\Code\Gw\Pref\PrApi.cpp", + "location < arrsize(s_flushDelay)", + 0, + -0x12); + + if (address is 0) + { + scopedLogger.LogError("Failed to find preferences initialized assertion"); + return 0; + } + + // Dereference to get actual address + var ptr = (nuint)Marshal.ReadIntPtr((nint)address); + if (ptr is 0) + { + scopedLogger.LogError("Failed to dereference preferences initialized address"); + return 0; + } + + scopedLogger.LogInformation("Preferences initialized address: 0x{address:X8}", ptr); + return ptr; + } + + private nuint GetGetEnumPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindUseOfString("pref < PREF_ENUMS"); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find 'pref < PREF_ENUMS' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve GetEnumPreference function start"); + return 0; + } + + scopedLogger.LogInformation("GetEnumPreference address: 0x{address:X8}", address); + return address; + } + + private nuint GetSetEnumPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindUseOfString("tableCount"); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find 'tableCount' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve SetEnumPreference function start"); + return 0; + } + + scopedLogger.LogInformation("SetEnumPreference address: 0x{address:X8}", address); + return address; + } + + private nuint GetGetNumberPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindUseOfString("pref < PREF_VALUES"); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find 'pref < PREF_VALUES' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve GetNumberPreference function start"); + return 0; + } + + scopedLogger.LogInformation("GetNumberPreference address: 0x{address:X8}", address); + return address; + } + + private nuint GetSetNumberPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindNthUseOfString("pref < PREF_VALUES", 1); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find second 'pref < PREF_VALUES' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve SetNumberPreference function start"); + return 0; + } + + scopedLogger.LogInformation("SetNumberPreference address: 0x{address:X8}", address); + return address; + } + + private nuint GetGetFlagPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindUseOfString("pref < PREF_FLAGS"); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find 'pref < PREF_FLAGS' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve GetFlagPreference function start"); + return 0; + } + + scopedLogger.LogInformation("GetFlagPreference address: 0x{address:X8}", address); + return address; + } + + private nuint GetSetFlagPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindNthUseOfString("pref < PREF_FLAGS", 1); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find second 'pref < PREF_FLAGS' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve SetFlagPreference function start"); + return 0; + } + + scopedLogger.LogInformation("SetFlagPreference address: 0x{address:X8}", address); + return address; + } + + private nuint GetGetStringPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindUseOfString("pref < PREF_STRINGS"); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find 'pref < PREF_STRINGS' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve GetStringPreference function start"); + return 0; + } + + scopedLogger.LogInformation("GetStringPreference address: 0x{address:X8}", address); + return address; + } + + private nuint GetSetStringPreferenceAddress() + { + var scopedLogger = this.logger.CreateScopedLogger(); + var stringUsage = this.memoryScanningService.FindNthUseOfString("pref < PREF_STRINGS", 1); + if (stringUsage is 0) + { + scopedLogger.LogError("Failed to find second 'pref < PREF_STRINGS' string usage"); + return 0; + } + + var address = this.memoryScanningService.ToFunctionStart(stringUsage); + if (address is 0) + { + scopedLogger.LogError("Failed to resolve SetStringPreference function start"); + return 0; + } + + scopedLogger.LogInformation("SetStringPreference address: 0x{address:X8}", address); + return address; + } +} diff --git a/Daybreak.API/Services/Interop/UIContextService.cs b/Daybreak.API/Services/Interop/UIContextService.cs index 6daee7e4..eeb5e3a0 100644 --- a/Daybreak.API/Services/Interop/UIContextService.cs +++ b/Daybreak.API/Services/Interop/UIContextService.cs @@ -30,7 +30,7 @@ public sealed class UIContextService private const string FrameArrayFile = "\\Code\\Engine\\Frame\\FrMsg.cpp"; private const string FrameArrayAssertion = "frame"; - + private static readonly byte[] GetRootFrameSeq = [ 0xA1, 0x00, 0x00, 0x00, 0x00, // mov eax,[address] 0x05, 0xD8, 0xFE, 0xFF, 0xFF, // add eax,FFFFFED8 @@ -42,10 +42,6 @@ public sealed class UIContextService [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void SendUIMessageFunc(UIMessage uiMessage, nuint wParam, nuint lParam); - [SuppressUnmanagedCodeSecurity] - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void SetFrameFlagFunc(uint frameId, uint flag); - [SuppressUnmanagedCodeSecurity] [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate uint GetChildFrameIdFunc(uint parentFrameId, uint childOffset); @@ -58,10 +54,6 @@ public sealed class UIContextService [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate void ValidateAsyncDecodeStr(char* s, DecodeStrCallback callback, void* wParam); - [SuppressUnmanagedCodeSecurity] - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private unsafe delegate uint DoAsyncDecodeStr(char* encodedStr, DecodeStrCallback callback, void* wParam); - public unsafe delegate void DecodeStrCallback(void* param, char* s); private readonly SemaphoreSlim sendUiMessageSemaphore = new(1); @@ -77,7 +69,7 @@ public sealed class UIContextService private readonly GWFastCall sendFrameUIMessage; private readonly ILogger logger; - private CancellationTokenSource? cts = default; + private CancellationTokenSource? cts; public UIContextService( HashingService hashingService, @@ -236,7 +228,7 @@ public sealed class UIContextService return true; } - public unsafe bool SetFrameDisabled(WrappedPointer frame, bool disabled) + public bool SetFrameDisabled(WrappedPointer frame, bool disabled) { var scopedLogger = this.logger.CreateScopedLogger(); if (frame.IsNull) @@ -249,7 +241,7 @@ public sealed class UIContextService return true; } - public unsafe bool SetFrameVisible(WrappedPointer frame, bool visible) + public bool SetFrameVisible(WrappedPointer frame, bool visible) { var scopedLogger = this.logger.CreateScopedLogger(); if (frame.IsNull) @@ -317,7 +309,7 @@ public sealed class UIContextService return null; } - for(var i = 0; i < frameArray.Pointer->Size; i++) + for (var i = 0; i < frameArray.Pointer->Size; i++) { var frame = frameArray.Pointer->Buffer[i]; if (frame.Pointer is null || @@ -362,7 +354,7 @@ public sealed class UIContextService return this.hashingService.Hash(value); } - public unsafe void SendMessage(UIMessage message, nuint wParam, nuint lParam) + public void SendMessage(UIMessage message, nuint wParam, nuint lParam) { this.sendUiMessageSemaphore.Wait(); this.sendUiMessageHook.Continue(message, wParam, lParam); @@ -381,7 +373,6 @@ public sealed class UIContextService this.decodeStringSemaphore.Wait(); try { - var validateDecodeStrFnc = this.validateAsyncDecodeStr.GetDelegate(); if (validateDecodeStrFnc is null) { @@ -391,7 +382,7 @@ public sealed class UIContextService validateDecodeStrFnc(encoded, callback, (void*)callbackParam); } - catch(Exception e) + catch (Exception e) { scopedLogger.LogError(e, "Encountered exception while decoding string"); } diff --git a/Daybreak.API/Services/WebApplicationBuilderExtensions.cs b/Daybreak.API/Services/WebApplicationBuilderExtensions.cs index 28d235ac..c3a3065f 100644 --- a/Daybreak.API/Services/WebApplicationBuilderExtensions.cs +++ b/Daybreak.API/Services/WebApplicationBuilderExtensions.cs @@ -29,6 +29,7 @@ public static class WebApplicationBuilderExtensions builder.WithAddressService(); builder.WithAddressService(); builder.WithAddressService(); + builder.WithAddressService(); builder.WithHookAddressHostedService(); return builder; }