feat(interact): Phase B.4 Use / UseWithTarget / TeleToLifestone outbound

Click-to-interact wire layer. Adds the three most common "do a thing
to an object" GameActions that the UI triggers on left-click / use-item
contexts.

Wire layer:
- InteractRequests.BuildUse (0x0036): single target guid — click a
  door, loot a corpse, talk to an NPC, activate a lifestone, step on
  a portal.
- InteractRequests.BuildUseWithTarget (0x0035): source + target —
  key on locked door, scroll on self, salvage tool on item.
- InteractRequests.BuildTeleToLifestone (0x0063): no-arg recall. Fails
  server-side if not tied; reply comes back as GameEvent WeenieError.

Server reply for Use + UseWithTarget is GameEventType.UseDone (0x01C7)
carrying a WeenieError code (0 = success). Already parsed; wiring
into a "UseDone" event on CombatState-style holder can be a follow-up.

Tests (3 new): byte-exact encoding of all three builders.

Build green, 616 tests pass (up from 613).

Ref: r08 §3 rows 0x0035/0x0036/0x0063.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-18 17:18:36 +02:00
parent 62cf755e7d
commit 68efb60b49
2 changed files with 121 additions and 0 deletions

View file

@ -0,0 +1,45 @@
using System;
using System.Buffers.Binary;
using AcDream.Core.Net.Messages;
using Xunit;
namespace AcDream.Core.Net.Tests.Messages;
public sealed class InteractRequestsTests
{
[Fact]
public void BuildUse_WritesOpcode0x0036AndTarget()
{
byte[] body = InteractRequests.BuildUse(gameActionSequence: 2, targetGuid: 0xDEAD);
Assert.Equal(16, body.Length);
Assert.Equal(InteractRequests.UseOpcode,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8)));
Assert.Equal(0xDEADu,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12)));
}
[Fact]
public void BuildUseWithTarget_WritesBothGuids()
{
byte[] body = InteractRequests.BuildUseWithTarget(
gameActionSequence: 3, sourceGuid: 0x1000, targetGuid: 0x2000);
Assert.Equal(20, body.Length);
Assert.Equal(InteractRequests.UseWithTargetOpcode,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8)));
Assert.Equal(0x1000u,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12)));
Assert.Equal(0x2000u,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(16)));
}
[Fact]
public void BuildTeleToLifestone_IsEnvelopeOnly()
{
byte[] body = InteractRequests.BuildTeleToLifestone(gameActionSequence: 7);
Assert.Equal(12, body.Length);
Assert.Equal(InteractRequests.TeleToLifestoneOpcode,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8)));
}
}