feat(mosstank): add VTank-style automation PoC
This commit is contained in:
parent
f6fe0f2a4f
commit
4e6e9bc9d9
212 changed files with 49462 additions and 416 deletions
|
|
@ -1004,9 +1004,14 @@ public static class GameEventWiring
|
|||
{
|
||||
var p = AppraiseInfoParser.TryParse(e.Payload.Span);
|
||||
if (p is null) return;
|
||||
// Merge parsed properties into the item if we know about it.
|
||||
// Retain the property tables and the item's own spell manifest as
|
||||
// one projection. VTank consults the latter for proc weapons.
|
||||
if (p.Value.Success && items.Get(p.Value.Guid) is not null)
|
||||
items.UpdateProperties(p.Value.Guid, p.Value.Properties);
|
||||
items.UpdateAppraisal(
|
||||
p.Value.Guid,
|
||||
p.Value.Properties,
|
||||
p.Value.SpellBook,
|
||||
clientTime());
|
||||
if (p.Value.CreatureProfile is { HealthMax: > 0u } creature)
|
||||
combat.OnUpdateHealth(
|
||||
p.Value.Guid,
|
||||
|
|
@ -1020,8 +1025,8 @@ public static class GameEventWiring
|
|||
// spellbook arrives via PlayerDescription (0x0013), which uses
|
||||
// a different wire format (see WorldSession + LocalPlayerState
|
||||
// — feeds vitals from PrivateUpdateVital instead).
|
||||
// The appraised spellbook belongs to that item. The local player's
|
||||
// learned spell manifest arrives only in PlayerDescription.
|
||||
// The appraised spellbook now belongs to that item. The local
|
||||
// player's learned manifest arrives only in PlayerDescription.
|
||||
});
|
||||
|
||||
// ── Player ────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public static class InventoryActions
|
|||
public const uint DropItemOpcode = 0x001Bu;
|
||||
public const uint NoLongerViewingContentsOpcode = 0x0195u;
|
||||
public const uint SetInscriptionOpcode = 0x00BFu;
|
||||
public const uint CreateTinkeringToolOpcode = 0x027Du;
|
||||
|
||||
/// <summary>
|
||||
/// Merge stack A into stack B of the same item type. Server validates
|
||||
|
|
@ -205,4 +206,48 @@ public static class InventoryActions
|
|||
text.CopyTo(body, 18);
|
||||
return body;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salvage one or more carried items with an owned salvage tool. Retail
|
||||
/// <c>CM_Inventory::Event_CreateTinkeringTool @ 0x006AB830</c> writes the
|
||||
/// tool id followed by <c>PackableList<unsigned long></c>: u32 count,
|
||||
/// then the object ids in list order. The server replies with GameEvent
|
||||
/// <c>0x02B4 SalvageOperationsResult</c> and removes accepted source items.
|
||||
/// </summary>
|
||||
public static byte[] BuildCreateTinkeringTool(
|
||||
uint seq,
|
||||
uint toolGuid,
|
||||
IReadOnlyList<uint> itemGuids)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(itemGuids);
|
||||
if (toolGuid == 0u)
|
||||
throw new ArgumentOutOfRangeException(nameof(toolGuid));
|
||||
if (itemGuids.Count == 0)
|
||||
throw new ArgumentException(
|
||||
"At least one item is required for salvage.",
|
||||
nameof(itemGuids));
|
||||
|
||||
byte[] body = new byte[20 + (itemGuids.Count * sizeof(uint))];
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(body, GameActionEnvelope);
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), seq);
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(
|
||||
body.AsSpan(8),
|
||||
CreateTinkeringToolOpcode);
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(12), toolGuid);
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(
|
||||
body.AsSpan(16),
|
||||
checked((uint)itemGuids.Count));
|
||||
for (int index = 0; index < itemGuids.Count; index++)
|
||||
{
|
||||
uint itemGuid = itemGuids[index];
|
||||
if (itemGuid == 0u)
|
||||
throw new ArgumentException(
|
||||
"Salvage item ids must be non-zero.",
|
||||
nameof(itemGuids));
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(
|
||||
body.AsSpan(20 + (index * sizeof(uint))),
|
||||
itemGuid);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3268,6 +3268,19 @@ public sealed class WorldSession : IDisposable
|
|||
SendGameAction(InventoryActions.BuildStackableSplitTo3D(seq, stackGuid, amount));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send retail CreateTinkeringTool (0x027D), the salvage operation used by
|
||||
/// gmSalvageUI and VTank.
|
||||
/// </summary>
|
||||
public void SendSalvage(uint toolGuid, IReadOnlyList<uint> itemGuids)
|
||||
{
|
||||
uint seq = NextGameActionSequence();
|
||||
SendGameAction(InventoryActions.BuildCreateTinkeringTool(
|
||||
seq,
|
||||
toolGuid,
|
||||
itemGuids));
|
||||
}
|
||||
|
||||
/// <summary>Send retail QueryHealth (0x01BF). Server replies UpdateHealth (0x01C0).</summary>
|
||||
/// <remarks>
|
||||
/// Retail anchor: <c>CM_Combat::Event_QueryHealth</c> / <c>gmToolbarUI::HandleSelectionChanged:198635</c>
|
||||
|
|
|
|||
|
|
@ -2,55 +2,6 @@
|
|||
"version": 2,
|
||||
"dependencies": {
|
||||
"net10.0": {
|
||||
"BCnEncoder.Net": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.2.1, )",
|
||||
"resolved": "2.2.1",
|
||||
"contentHash": "tI5+/OQo0kciLqWrViRjpOH+IL3FjexYnoWZajiGV41g/EM9CGbWsxsPzBDmpoxNkrV9uox/EtIhCIi9chBSFw==",
|
||||
"dependencies": {
|
||||
"CommunityToolkit.HighPerformance": "8.4.0"
|
||||
}
|
||||
},
|
||||
"Chorizite.Core": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.0.18, )",
|
||||
"resolved": "0.0.18",
|
||||
"contentHash": "Pvf5idSsN0NfhZspJhrpo7QiNTmHx3mnKFkmAvHFpEFx+RnqfXh96Q+Pxam+hrqXbimmKGfk1ooIl5kpQcMo6w==",
|
||||
"dependencies": {
|
||||
"Autofac": "8.4.0",
|
||||
"Chorizite.ACProtocol": "1.0.1",
|
||||
"Chorizite.Common": "1.0.3",
|
||||
"Chorizite.DatReaderWriter": "1.0.0",
|
||||
"FontStashSharp": "1.3.10",
|
||||
"Microsoft.Diagnostics.Runtime": "3.1.512801",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||
"NJsonSchema": "11.5.1",
|
||||
"SixLabors.ImageSharp": "3.1.11",
|
||||
"SixLabors.ImageSharp.Drawing": "2.1.7"
|
||||
}
|
||||
},
|
||||
"Chorizite.DatReaderWriter": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.1.7, )",
|
||||
"resolved": "2.1.7",
|
||||
"contentHash": "6CpUhfHDV/O+lNx0xUZUcXK7wGkEkHYCnGHFtD8BBeAv4i1BuaNfTID+VQoSzx2EtmOVM0A2O/9wRFibApz6rQ==",
|
||||
"dependencies": {
|
||||
"DotNet.Standard.Common": "2.0.1",
|
||||
"ZLibDotNet": "0.1.1"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.0.2, )",
|
||||
"resolved": "4.0.2",
|
||||
"contentHash": "Vehq4uNYtURe/OnHEpWGvMgrvr5Vou7oZLdn3BuEH5FSCeHXDpNJtpzWoqywXsSvCTuiv0I65mZDRnJSeUvisA=="
|
||||
},
|
||||
"StbImageSharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.30.16, )",
|
||||
"resolved": "2.30.16",
|
||||
"contentHash": "qg1i+NHihXVKLKYacGKrauhSQIGL31eBWcTC4Vc7jnGmBFj87LkRuCdXB5aDZisWMRnB6x2mcfwYXQxMWEG/lw=="
|
||||
},
|
||||
"Autofac": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.4.0",
|
||||
|
|
@ -245,9 +196,57 @@
|
|||
"resolved": "0.1.1",
|
||||
"contentHash": "QEti4O7dwRcOb9zbnLuudSrt2IT61OYjq0R7lcJb+EzUm5N6djOVGU/cp+FZIZzJUnaFIntwrpwiuRvhpS7ZHg=="
|
||||
},
|
||||
"acdream.core": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AcDream.Plugin.Abstractions": "[1.0.0, )",
|
||||
"BCnEncoder.Net": "[2.2.1, )",
|
||||
"Chorizite.Core": "[0.0.18, )",
|
||||
"Chorizite.DatReaderWriter": "[2.1.7, )",
|
||||
"Serilog": "[4.0.2, )",
|
||||
"StbImageSharp": "[2.30.16, )"
|
||||
}
|
||||
},
|
||||
"acdream.plugin.abstractions": {
|
||||
"type": "Project"
|
||||
},
|
||||
"BCnEncoder.Net": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.1, )",
|
||||
"resolved": "2.2.1",
|
||||
"contentHash": "tI5+/OQo0kciLqWrViRjpOH+IL3FjexYnoWZajiGV41g/EM9CGbWsxsPzBDmpoxNkrV9uox/EtIhCIi9chBSFw==",
|
||||
"dependencies": {
|
||||
"CommunityToolkit.HighPerformance": "8.4.0"
|
||||
}
|
||||
},
|
||||
"Chorizite.Core": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[0.0.18, )",
|
||||
"resolved": "0.0.18",
|
||||
"contentHash": "Pvf5idSsN0NfhZspJhrpo7QiNTmHx3mnKFkmAvHFpEFx+RnqfXh96Q+Pxam+hrqXbimmKGfk1ooIl5kpQcMo6w==",
|
||||
"dependencies": {
|
||||
"Autofac": "8.4.0",
|
||||
"Chorizite.ACProtocol": "1.0.1",
|
||||
"Chorizite.Common": "1.0.3",
|
||||
"Chorizite.DatReaderWriter": "1.0.0",
|
||||
"FontStashSharp": "1.3.10",
|
||||
"Microsoft.Diagnostics.Runtime": "3.1.512801",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||
"NJsonSchema": "11.5.1",
|
||||
"SixLabors.ImageSharp": "3.1.11",
|
||||
"SixLabors.ImageSharp.Drawing": "2.1.7"
|
||||
}
|
||||
},
|
||||
"Chorizite.DatReaderWriter": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.1.7, )",
|
||||
"resolved": "2.1.7",
|
||||
"contentHash": "6CpUhfHDV/O+lNx0xUZUcXK7wGkEkHYCnGHFtD8BBeAv4i1BuaNfTID+VQoSzx2EtmOVM0A2O/9wRFibApz6rQ==",
|
||||
"dependencies": {
|
||||
"DotNet.Standard.Common": "2.0.1",
|
||||
"ZLibDotNet": "0.1.1"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[9.0.9, )",
|
||||
|
|
@ -257,12 +256,24 @@
|
|||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[4.0.2, )",
|
||||
"resolved": "4.0.2",
|
||||
"contentHash": "Vehq4uNYtURe/OnHEpWGvMgrvr5Vou7oZLdn3BuEH5FSCeHXDpNJtpzWoqywXsSvCTuiv0I65mZDRnJSeUvisA=="
|
||||
},
|
||||
"SixLabors.ImageSharp": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.1.12, )",
|
||||
"resolved": "3.1.11",
|
||||
"contentHash": "JfPLyigLthuE50yi6tMt7Amrenr/fA31t2CvJyhy/kQmfulIBAqo5T/YFUSRHtuYPXRSaUHygFeh6Qd933EoSw=="
|
||||
},
|
||||
"StbImageSharp": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.30.16, )",
|
||||
"resolved": "2.30.16",
|
||||
"contentHash": "qg1i+NHihXVKLKYacGKrauhSQIGL31eBWcTC4Vc7jnGmBFj87LkRuCdXB5aDZisWMRnB6x2mcfwYXQxMWEG/lw=="
|
||||
},
|
||||
"StbTrueTypeSharp": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.26.12, )",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue