using Ananta.SDK.Serialization; namespace Ananta.Server.Protocol.Client4229938; // Native 4229938 S002PlayerNet / S002.Interact.SInteractNet. Shares the story // channel's cumulative RPC acknowledgement with S011; never resets it here. internal static class StoryS002Codec4229938 { // Wire names come from the native constructors, NOT the C# member names. // S002PlayerNet ctor RVA 0x15F77A30: MsgrNpcInteract => "NpcInteract". // SInteractNet ctor RVA 0x15F6D120: ObsInteractEnd => "InteractEnd"; // MsgrInteraction/MsgrReaction/MsgrClient => "Interaction"/"Reaction"/"Messenger". // A wrong observable name throws in NetNode.ApplyEnableData before OnEnable. internal const string NpcInteract = "NpcInteract"; internal const string InteractEnd = "InteractEnd"; internal const string InteractionMessage = "Interaction"; internal const string ReactionMessage = "Reaction"; internal const string ClientMessage = "Messenger"; // Root NpcInteract payload marks, NOT child InteractionId values. // Verified in the actual client's generated serialization instructions: // WriteS002EscortFromRequestPayload_Check 0x9F56600 (+0x93) writes 0x14; // WriteS002EscortRequestPayload_Check 0x9F56710 (+0x93) writes 0x15. // Their declaration/TypeDef order is different from their wire mark order. internal const byte EnterExamRequestTag = 19; internal const byte EscortFromVehicleRequestTag = 20; internal const byte EscortRequestTag = 21; internal static byte[] Root(uint nid) { var w = new UxWriter(); List(w, 3); Create(w, nid, "StoryServer.Story.World.S002.S002PlayerNet"); Validate(w, nid, [], [], [NpcInteract]); w.U8(6); w.U32(nid); w.U8(0); w.U8(0); w.U8(0); Tail(w); return w.ToArray(); } internal static byte[] Interaction(uint nid, ulong agent, bool start, bool escort = false, bool serverInitiate = false) { var w = new UxWriter(); List(w, 3); Create(w, nid, "StoryServer.Story.World.S002.Interact.SInteractNet"); Validate(w, nid, ["ExamEmotionId", InteractEnd], ["AgentId", "IsEscort", "IsFakePerson", "ServerInitiate", "StartInteract"], [InteractionMessage, ReactionMessage, ClientMessage]); w.U8(6); w.U32(nid); List(w, 2); Named(w, "ExamEmotionId", b => { b.U8(43); b.U32(0); }); Named(w, InteractEnd, b => { b.U8(5); b.Bool(false); }); List(w, 5); Named(w, "AgentId", b => { b.U8(44); b.U64(agent); }); Named(w, "IsEscort", b => { b.U8(5); b.Bool(escort); }); Named(w, "IsFakePerson", b => { b.U8(5); b.Bool(false); }); Named(w, "ServerInitiate", b => { b.U8(5); b.Bool(serverInitiate); }); Named(w, "StartInteract", b => { b.U8(5); b.Bool(start); }); w.U8(0); Tail(w); return w.ToArray(); } internal static byte[] Reaction(uint nid, uint section, uint reaction, uint escortToWardIndex = 0) { var w = new UxWriter(); List(w, 1); w.U8(7); w.U32(nid); w.UxString(ReactionMessage); // S002ReactionResponsePayload: SectionId, ReactionId, EscortToWardIndex, // EscortToHearCaseId. The ward index is consumed by SEscortToWard. w.U8(26); w.U32(section); w.U32(reaction); w.U32(escortToWardIndex); w.U64(0); Tail(w); return w.ToArray(); } private static void Create(UxWriter w, uint nid, string type) { w.U8(3); w.U32(nid); w.UxString(type); w.UxString(""); w.Bool(false); Tail(w); } private static void Validate(UxWriter w, uint nid, string[] obs, string[] repl, string[] msg) { w.U8(9); w.U32(nid); Strings(w, obs); Strings(w, repl); Strings(w, msg); w.U8(0); Tail(w); } private static void Strings(UxWriter w, string[] values) { List(w, values.Length); foreach (var value in values) w.UxString(value); } private static void Named(UxWriter w, string name, Action payload) { w.U8(255); w.UxString(name); payload(w); } private static void List(UxWriter w, int count) { w.U8(255); w.Int7(count); } private static void Tail(UxWriter w) { w.I64(0); w.Bool(false); } }