fix(inventory): await final wield confirmation
Keep the retail inventory transaction busy until authoritative WieldObject confirms the requested weapon. This prevents rapid weapon changes from overlapping on ACE and rejecting otherwise valid items such as spears. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
815ce0dec4
commit
ea5cf5b842
8 changed files with 115 additions and 9 deletions
|
|
@ -485,12 +485,54 @@ public sealed class ItemInteractionControllerTests
|
|||
|
||||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
h.Now += 200;
|
||||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
Assert.False(h.Controller.ActivateItem(bow));
|
||||
|
||||
Assert.Single(h.Puts);
|
||||
Assert.Empty(h.Wields);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WeaponReplacement_doesNotOverlapWhileAwaitingFinalWieldConfirmation()
|
||||
{
|
||||
var h = new Harness();
|
||||
const uint sword = 0x50000B15u;
|
||||
const uint bow = 0x50000B16u;
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = sword,
|
||||
Type = ItemType.MeleeWeapon,
|
||||
CombatUse = 1,
|
||||
ValidLocations = EquipMask.MeleeWeapon,
|
||||
});
|
||||
h.Objects.MoveItem(sword, Player, -1, EquipMask.MeleeWeapon);
|
||||
h.AddContained(bow, item =>
|
||||
{
|
||||
item.Type = ItemType.MissileWeapon;
|
||||
item.CombatUse = 2;
|
||||
item.ValidLocations = EquipMask.MissileWeapon;
|
||||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
h.Objects.MoveItem(sword, Player, 0, EquipMask.None);
|
||||
Assert.Single(h.Wields);
|
||||
|
||||
// Bow is optimistic but ACE has not sent WieldObject yet. Retail's
|
||||
// waiting state consumes this attempted reverse switch.
|
||||
h.Now += 200;
|
||||
Assert.False(h.Controller.ActivateItem(sword));
|
||||
Assert.Single(h.Puts);
|
||||
Assert.Single(h.Wields);
|
||||
|
||||
// Authoritative WieldObject + ConfirmMove completes the transaction.
|
||||
h.Objects.MoveItem(bow, Player, -1, EquipMask.MissileWeapon);
|
||||
h.Objects.ConfirmMove(bow);
|
||||
h.Now += 200;
|
||||
Assert.True(h.Controller.ActivateItem(sword));
|
||||
Assert.Equal(
|
||||
new[] { (sword, Player, 0), (bow, Player, 0) },
|
||||
h.Puts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WeaponReplacement_serverReject_clearsPendingTransactionForRetry()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -743,6 +743,25 @@ public sealed class ClientObjectTableTests
|
|||
seen);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConfirmMove_publishesOnlyAfterFinalOutstandingRequest()
|
||||
{
|
||||
var table = new ClientObjectTable();
|
||||
const uint item = 0x944u, player = 0x50000001u, pack = 0x40000005u;
|
||||
table.AddOrUpdate(new ClientObject { ObjectId = item });
|
||||
table.MoveItem(item, pack, 2);
|
||||
table.WieldItemOptimistic(item, player, EquipMask.MeleeWeapon);
|
||||
table.MoveItemOptimistic(item, pack, 0);
|
||||
var confirmed = new List<uint>();
|
||||
table.MoveRequestConfirmed += moved => confirmed.Add(moved.ObjectId);
|
||||
|
||||
table.ConfirmMove(item);
|
||||
Assert.Empty(confirmed);
|
||||
|
||||
table.ConfirmMove(item);
|
||||
Assert.Equal(new[] { item }, confirmed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WieldThenMove_oneConfirm_rollsBackToPreWield() // outstanding-count across wield+move (shared RecordPending)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue