feat(mosstank): add VTank-style automation PoC

This commit is contained in:
Erik 2026-08-27 18:57:21 +02:00
parent f6fe0f2a4f
commit 4e6e9bc9d9
212 changed files with 49462 additions and 416 deletions

View file

@ -0,0 +1,117 @@
namespace AcDream.Plugin.Abstractions;
/// <summary>
/// Virindi/Decal's stable ObjectClass numbers. These are deliberately distinct
/// from retail's ItemType flags: expressions and imported metas commonly use
/// numeric ObjectClass values (for example 5 = Monster and 24 = Player).
/// </summary>
public enum PluginObjectClass
{
Unknown = 0,
MeleeWeapon = 1,
Armor = 2,
Clothing = 3,
Jewelry = 4,
Monster = 5,
Food = 6,
Money = 7,
Misc = 8,
MissileWeapon = 9,
Container = 10,
Gem = 11,
SpellComponent = 12,
Key = 13,
Portal = 14,
TradeNote = 15,
ManaStone = 16,
Plant = 17,
BaseCooking = 18,
BaseAlchemy = 19,
BaseFletching = 20,
CraftedCooking = 21,
CraftedAlchemy = 22,
CraftedFletching = 23,
Player = 24,
Vendor = 25,
Door = 26,
Corpse = 27,
Lifestone = 28,
HealingKit = 29,
Lockpick = 30,
WandStaffOrb = 31,
Bundle = 32,
Book = 33,
Journal = 34,
Sign = 35,
Housing = 36,
Npc = 37,
Foci = 38,
Salvage = 39,
Ust = 40,
Services = 41,
Scroll = 42,
CombatPet = 43,
}
/// <summary>
/// Detached canonical world-object projection for general plugins and
/// expression engines. The host reports facts; filtering and automation
/// policy remain in the plugin.
/// </summary>
public readonly record struct PluginWorldObject(
uint ObjectId,
uint WeenieClassId,
string Name,
PluginObjectClass ObjectClass,
uint ItemType,
uint ContainerObjectId,
uint WielderObjectId)
{
public bool IsOwned { get; init; }
public bool IsLandscape { get; init; }
public bool HasPosition { get; init; }
public PluginNavigationPosition Position { get; init; }
public bool HasAppraisalData { get; init; }
/// <summary>
/// Decal-compatible monotonic millisecond tick of the latest successful
/// identify response for this exact object lifetime.
/// </summary>
public int LastIdTime { get; init; }
public bool IsDoorOpen { get; init; }
public int StackSize { get; init; } = 1;
public int ItemsCapacity { get; init; }
public int ContainersCapacity { get; init; }
public IReadOnlyList<uint> SpellIds { get; init; } = Array.Empty<uint>();
public IReadOnlyList<uint> ActiveSpellIds { get; init; } = Array.Empty<uint>();
}
/// <summary>
/// General object discovery used by UtilityBelt expressions and third-party
/// plugins. It borrows the same Runtime entity directory and ClientObject table
/// as world rendering and inventory; no plugin-specific mirror is introduced.
/// </summary>
public interface IWorldObjectAutomation
{
bool IsAvailable => false;
uint OpenContainerObjectId => 0u;
IReadOnlyList<PluginWorldObject> CaptureObjects() =>
Array.Empty<PluginWorldObject>();
bool TryGet(uint objectId, out PluginWorldObject value)
{
value = default;
return false;
}
bool TryCaptureProperties(
uint objectId,
out PluginItemProperties properties)
{
properties = default;
return false;
}
PluginItemCommandResult Identify(uint objectId) =>
new(PluginItemCommandStatus.Unavailable);
}