fix #211: index login-equipped items under player
Project PlayerDescription equipment through the same contained-by-wielder ownership and ordered contents index as live WieldObject updates. Preserve equip masks and priorities so retail GetObjectAtLocation selects Missile for an already-equipped crossbow instead of sending a server-rejected Melee request. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
e74efc5c06
commit
ab98cda26b
6 changed files with 150 additions and 12 deletions
|
|
@ -452,6 +452,61 @@ public sealed class GameEventWiringTests
|
|||
Assert.Equal(1u, items.Get(0x50000A02u)!.ContainerTypeHint);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlayerDescription_IndexesLoginEquipmentForDefaultCombatMode()
|
||||
{
|
||||
const uint playerGuid = 0x50000001u;
|
||||
const uint packItemGuid = 0x50000A01u;
|
||||
const uint crossbowGuid = 0x50000B01u;
|
||||
var dispatcher = new GameEventDispatcher();
|
||||
var items = new ClientObjectTable();
|
||||
GameEventWiring.WireAll(
|
||||
dispatcher,
|
||||
items,
|
||||
new CombatState(),
|
||||
new Spellbook(),
|
||||
new ChatLog(),
|
||||
playerGuid: () => playerGuid);
|
||||
|
||||
var sb = new MemoryStream();
|
||||
using var w = new BinaryWriter(sb);
|
||||
w.Write(0u); // propertyFlags
|
||||
w.Write(0x52u); // weenieType
|
||||
w.Write(0x201u); // ATTRIBUTE | ENCHANTMENT
|
||||
w.Write(1u); // has_health
|
||||
w.Write(0u); // attribute_flags
|
||||
w.Write(0u); // enchantment_mask
|
||||
w.Write(0u); // option_flags
|
||||
w.Write(0u); // options1
|
||||
w.Write(0u); // legacy hotbar count
|
||||
w.Write(0u); // spellbook_filters
|
||||
w.Write(1u); // inventory count
|
||||
w.Write(packItemGuid); w.Write(0u);
|
||||
w.Write(1u); // equipped count
|
||||
w.Write(crossbowGuid);
|
||||
w.Write((uint)EquipMask.MissileWeapon);
|
||||
w.Write(7u); // layering priority
|
||||
|
||||
var envelope = GameEventEnvelope.TryParse(
|
||||
WrapEnvelope(GameEventType.PlayerDescription, sb.ToArray()));
|
||||
dispatcher.Dispatch(envelope!.Value);
|
||||
|
||||
ClientObject crossbow = items.Get(crossbowGuid)!;
|
||||
crossbow.Type = ItemType.MissileWeapon;
|
||||
crossbow.CombatUse = 2;
|
||||
var orderedPlayerContents = items.GetContents(playerGuid)
|
||||
.Select(guid => items.Get(guid)!)
|
||||
.ToList();
|
||||
|
||||
Assert.Equal(new[] { packItemGuid, crossbowGuid }, items.GetContents(playerGuid));
|
||||
Assert.Equal(playerGuid, crossbow.ContainerId);
|
||||
Assert.Equal(EquipMask.MissileWeapon, crossbow.CurrentlyEquippedLocation);
|
||||
Assert.Equal(7u, crossbow.Priority);
|
||||
Assert.Equal(
|
||||
CombatMode.Missile,
|
||||
CombatInputPlanner.GetDefaultCombatMode(orderedPlayerContents));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WireAll_QueryItemManaResponse_RoutesValidityToItemManaState()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -359,6 +359,28 @@ public sealed class ClientObjectTableTests
|
|||
Assert.Equal(0u, o.IconId); // data not set — CreateObject fills it
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordMembership_OwnedEquip_UsesSameIndexShapeAsLiveWield()
|
||||
{
|
||||
const uint playerGuid = 0x50000001u;
|
||||
const uint weaponGuid = 0x500000B9u;
|
||||
var table = new ClientObjectTable();
|
||||
|
||||
table.RecordMembership(
|
||||
weaponGuid,
|
||||
containerId: playerGuid,
|
||||
equip: EquipMask.MissileWeapon,
|
||||
priority: 7u);
|
||||
|
||||
var weapon = table.Get(weaponGuid);
|
||||
Assert.NotNull(weapon);
|
||||
Assert.Equal(playerGuid, weapon!.ContainerId);
|
||||
Assert.Equal(-1, weapon.ContainerSlot);
|
||||
Assert.Equal(EquipMask.MissileWeapon, weapon.CurrentlyEquippedLocation);
|
||||
Assert.Equal(7u, weapon.Priority);
|
||||
Assert.Equal(new[] { weaponGuid }, table.GetContents(playerGuid));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ingest_AfterMembership_FillsData_NoDuplicate() // out-of-order: PD then CreateObject
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue