feat(inventory): port retail weapon switching
Sequence primary weapon replacement through the server-confirmed AutoWield transaction: return the occupied weapon to the player pack, wait for its move event, then wield the requested item. Route authoritative CombatMode property updates so peace stays peace and war adopts the new weapon stance without client-synthesized animation. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
8e9c538519
commit
17b5712d53
14 changed files with 736 additions and 155 deletions
47
src/AcDream.Core.Net/CombatStateWiring.cs
Normal file
47
src/AcDream.Core.Net/CombatStateWiring.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
using AcDream.Core.Combat;
|
||||
|
||||
namespace AcDream.Core.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Routes the local player's server-owned combat-mode quality into
|
||||
/// <see cref="CombatState"/>. Retail
|
||||
/// <c>ClientCombatSystem::OnQualityChanged @ 0x0056C1B0</c> reads
|
||||
/// PropertyInt 40 and calls <c>SetCombatMode</c> on every change.
|
||||
/// </summary>
|
||||
public static class CombatStateWiring
|
||||
{
|
||||
public const uint CombatModePropertyId = 40u;
|
||||
|
||||
public static void Wire(WorldSession session, CombatState combat)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(session);
|
||||
ArgumentNullException.ThrowIfNull(combat);
|
||||
|
||||
session.PlayerIntPropertyUpdated += update =>
|
||||
ApplyPlayerIntProperty(combat, update.Property, update.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pure event adapter exposed for conformance tests. Composite or unknown
|
||||
/// values are ignored: retail's quality contains one concrete mode.
|
||||
/// </summary>
|
||||
public static bool ApplyPlayerIntProperty(
|
||||
CombatState combat,
|
||||
uint property,
|
||||
int value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(combat);
|
||||
if (property != CombatModePropertyId)
|
||||
return false;
|
||||
|
||||
CombatMode mode = (CombatMode)value;
|
||||
if (mode is not (CombatMode.NonCombat
|
||||
or CombatMode.Melee
|
||||
or CombatMode.Missile
|
||||
or CombatMode.Magic))
|
||||
return false;
|
||||
|
||||
combat.SetCombatMode(mode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -314,7 +314,7 @@ public static class GameEventWiring
|
|||
string itemInfo = item is null
|
||||
? "unknown"
|
||||
: $"'{item.Name}' valid=0x{(uint)item.ValidLocations:X8} equip=0x{(uint)item.CurrentlyEquippedLocation:X8} priority=0x{item.Priority:X8} container=0x{item.ContainerId:X8} wielder=0x{item.WielderId:X8}";
|
||||
bool rolledBack = items.RollbackMove(p.Value.ItemGuid);
|
||||
bool rolledBack = items.RejectMove(p.Value.ItemGuid, p.Value.WeenieError);
|
||||
Console.WriteLine($"[B-Drag] InventoryServerSaveFailed guid=0x{p.Value.ItemGuid:X8} err=0x{p.Value.WeenieError:X} rolledBack={rolledBack} item={itemInfo}");
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue