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
|
|
@ -251,6 +251,21 @@ public sealed class ClientObject
|
|||
/// <summary>Retail <c>PublicWeenieDesc._spellID</c>; used by caster endowments.</summary>
|
||||
public uint? SpellId { get; set; }
|
||||
/// <summary>
|
||||
/// Spell ids retained from this item's latest successful
|
||||
/// <c>IdentifyObjectResponse</c> SpellBook block. These are item spells,
|
||||
/// not the local character's learned spellbook; VTank uses them to
|
||||
/// classify cast-on-strike weapons and item-cast debuffs.
|
||||
/// </summary>
|
||||
public IReadOnlyList<uint> AppraisedSpellIds { get; internal set; } =
|
||||
Array.Empty<uint>();
|
||||
/// <summary>
|
||||
/// Monotonic millisecond tick at which the latest successful identify
|
||||
/// response was received. This is Decal's per-world-object
|
||||
/// <c>LastIdTime</c>, retained on the canonical object so it disappears
|
||||
/// with that exact object lifetime.
|
||||
/// </summary>
|
||||
public int LastAppraisalTimeMs { get; internal set; }
|
||||
/// <summary>
|
||||
/// Retail <c>PublicWeenieDesc._cooldown_id</c>. Positive values name a
|
||||
/// shared item-cooldown group whose player enchantment id is
|
||||
/// <c>CooldownId + 0x8000</c>.
|
||||
|
|
|
|||
|
|
@ -774,6 +774,45 @@ public sealed class ClientObjectTable
|
|||
public bool UpdateProperties(uint itemId, PropertyBundle incoming)
|
||||
{
|
||||
if (!_objects.TryGetValue(itemId, out var item)) return false;
|
||||
MergeProperties(item, incoming);
|
||||
ApplyCooldownProperties(item, incoming);
|
||||
ObjectUpdated?.Invoke(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Atomically retains every successful item-appraisal result: the typed
|
||||
/// property tables and the per-item SpellBook block. Publishing one update
|
||||
/// prevents observers from seeing properties without their matching spell
|
||||
/// manifest (or the reverse).
|
||||
/// </summary>
|
||||
public bool UpdateAppraisal(
|
||||
uint itemId,
|
||||
PropertyBundle incoming,
|
||||
IReadOnlyList<uint> spellIds,
|
||||
double receivedAtSeconds = 0d)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(incoming);
|
||||
ArgumentNullException.ThrowIfNull(spellIds);
|
||||
if (!_objects.TryGetValue(itemId, out var item)) return false;
|
||||
MergeProperties(item, incoming);
|
||||
item.AppraisedSpellIds = spellIds.Count == 0
|
||||
? Array.Empty<uint>()
|
||||
: spellIds.ToArray();
|
||||
if (double.IsFinite(receivedAtSeconds) && receivedAtSeconds >= 0d)
|
||||
{
|
||||
long milliseconds = checked((long)Math.Round(
|
||||
receivedAtSeconds * 1000d,
|
||||
MidpointRounding.AwayFromZero));
|
||||
item.LastAppraisalTimeMs = unchecked((int)milliseconds);
|
||||
}
|
||||
ApplyCooldownProperties(item, incoming);
|
||||
ObjectUpdated?.Invoke(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void MergeProperties(ClientObject item, PropertyBundle incoming)
|
||||
{
|
||||
foreach (var kv in incoming.Ints) item.Properties.Ints[kv.Key] = kv.Value;
|
||||
foreach (var kv in incoming.Int64s) item.Properties.Int64s[kv.Key] = kv.Value;
|
||||
foreach (var kv in incoming.Bools) item.Properties.Bools[kv.Key] = kv.Value;
|
||||
|
|
@ -781,9 +820,6 @@ public sealed class ClientObjectTable
|
|||
foreach (var kv in incoming.Strings) item.Properties.Strings[kv.Key] = kv.Value;
|
||||
foreach (var kv in incoming.DataIds) item.Properties.DataIds[kv.Key] = kv.Value;
|
||||
foreach (var kv in incoming.InstanceIds) item.Properties.InstanceIds[kv.Key] = kv.Value;
|
||||
ApplyCooldownProperties(item, incoming);
|
||||
ObjectUpdated?.Invoke(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue