diff --git a/ChatTwo/GameFunctions/GameFunctions.cs b/ChatTwo/GameFunctions/GameFunctions.cs index 532f64a..28f5080 100755 --- a/ChatTwo/GameFunctions/GameFunctions.cs +++ b/ChatTwo/GameFunctions/GameFunctions.cs @@ -29,6 +29,9 @@ internal unsafe class GameFunctions : IDisposable { [Signature("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 E8 ?? ?? ?? ?? 48 8B 8B ?? ?? ?? ?? 48 85 C9", Fallibility = Fallibility.Fallible)] private readonly delegate* unmanaged _openPartyFinder = null!; + [Signature("E8 ?? ?? ?? ?? EB 42 48 8B 47 30", Fallibility = Fallibility.Fallible)] + private readonly delegate* unmanaged _openAchievement = null!; + #endregion #region Hooks @@ -240,6 +243,17 @@ internal unsafe class GameFunctions : IDisposable { } } + internal void OpenAchievement(uint id) { + if (this._openAchievement == null) { + return; + } + + var agent = Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.Achievement); + if (agent != null) { + this._openAchievement(agent, id); + } + } + private readonly IntPtr _placeholderNamePtr = Marshal.AllocHGlobal(128); private readonly string _placeholder = $"<{Guid.NewGuid():N}>"; private string? _replacementName; diff --git a/ChatTwo/PayloadHandler.cs b/ChatTwo/PayloadHandler.cs index bc2213d..020a34d 100755 --- a/ChatTwo/PayloadHandler.cs +++ b/ChatTwo/PayloadHandler.cs @@ -190,6 +190,10 @@ internal sealed class PayloadHandler { this.Ui.Plugin.Functions.OpenPartyFinder(pf.Id); break; } + case AchievementPayload achievement: { + this.Ui.Plugin.Functions.OpenAchievement(achievement.Id); + break; + } case RawPayload raw: { if (Equals(raw, ChunkUtil.PeriodicRecruitmentLink)) { GameFunctions.GameFunctions.OpenPartyFinder(); diff --git a/ChatTwo/Util/ChunkUtil.cs b/ChatTwo/Util/ChunkUtil.cs index 5e3997f..4674da1 100755 --- a/ChatTwo/Util/ChunkUtil.cs +++ b/ChatTwo/Util/ChunkUtil.cs @@ -73,6 +73,11 @@ internal static class ChunkUtil { var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..])); var id = GetInteger(reader); link = new PartyFinderPayload(id); + } else if (rawPayload.Data.Length > 5 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x06) { + // achievement payload + var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..])); + var id = GetInteger(reader); + link = new AchievementPayload(id); } else if (Equals(rawPayload, RawPayload.LinkTerminator)) { link = null; } else if (Equals(rawPayload, PeriodicRecruitmentLink)) { diff --git a/ChatTwo/Util/Payloads.cs b/ChatTwo/Util/Payloads.cs index 8808ffc..c69bd93 100755 --- a/ChatTwo/Util/Payloads.cs +++ b/ChatTwo/Util/Payloads.cs @@ -19,3 +19,21 @@ internal class PartyFinderPayload : Payload { throw new NotImplementedException(); } } + +internal class AchievementPayload : Payload { + public override PayloadType Type => (PayloadType) 0x51; + + internal uint Id { get; } + + internal AchievementPayload(uint id) { + this.Id = id; + } + + protected override byte[] EncodeImpl() { + throw new NotImplementedException(); + } + + protected override void DecodeImpl(BinaryReader reader, long endOfStream) { + throw new NotImplementedException(); + } +}