This repository has been archived on 2026-10-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Ananta-ps/Ananta.Server/Ananta.Core/Protocol/Client4229938/StoryS002Codec4229938.cs
T

80 lines
4.1 KiB
C#

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<UxWriter> 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); }
}