# Plugin Architecture **Referenced Files in This Document** - [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs) - [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs) - [Program.cs](file://ClassicAssist.Avalonia/Program.cs) - [Extension.cs](file://ClassicAssist.Shared/Data/Extension.cs) - [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs) - [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs) - [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs) - [HotkeyCommandAttribute.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs) - [HotkeyCommand.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs) - [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs) - [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs) - [PacketFilter.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs) - [PacketFilterInfo.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs) - [PluginEntry.cs](file://ClassicAssist.Launcher/PluginEntry.cs) - [ManifestEntry.cs](file://ClassicAssist.Launcher/ManifestEntry.cs) ## Table of Contents 1. [Introduction](#introduction) 2. [Project Structure](#project-structure) 3. [Core Components](#core-components) 4. [Architecture Overview](#architecture-overview) 5. [Detailed Component Analysis](#detailed-component-analysis) 6. [Dependency Analysis](#dependency-analysis) 7. [Performance Considerations](#performance-considerations) 8. [Security Considerations](#security-considerations) 9. [Troubleshooting Guide](#troubleshooting-guide) 10. [Conclusion](#conclusion) 11. [Appendices](#appendices) ## Introduction This document explains the plugin architecture and extension system for ClassicAssist.Avalonia. It covers how plugins are discovered and loaded, the interfaces that define extensibility points, how commands and hotkeys are registered, the macro command framework (including parameter parsing and execution context), the filter system for message processing and data transformation, lifecycle management and dependency resolution, version compatibility checks, and security considerations such as sandboxing and permissions. It also provides practical guidelines for developing custom plugins and extensions. ## Project Structure The repository is organized into multiple projects: - ClassicAssist.Shared: Core runtime, shared models, macro and hotkey frameworks, packet filtering, and UI abstractions. - ClassicAssist.Avalonia: Avalonia-based UI entry point and engine integration. - ClassicAssist.Launcher: Launcher with manifest and plugin entry metadata. - ClassicAssist.UO: Game networking, packets, and object model. - ClassicAssist.Tests: Unit tests for core features. ```mermaid graph TB subgraph "Launcher" L_Program["Program.cs"] L_PluginEntry["PluginEntry.cs"] L_ManifestEntry["ManifestEntry.cs"] end subgraph "Avalonia App" A_Program["Program.cs"] A_App["App.axaml.cs"] A_Engine["Engine.cs"] end subgraph "Shared Runtime" S_Extension["Extension.cs"] S_MacroMgr["MacroManager.cs"] S_MacroInv["MacroInvoker.cs"] S_HotkeyMgr["HotkeyManager.cs"] S_HotkeyCmdAttr["HotkeyCommandAttribute.cs"] S_HotkeyCmd["HotkeyCommand.cs"] S_InPktFilters["IncomingPacketFilters.cs"] S_OutPktFilters["OutgoingPacketFilters.cs"] S_PktFilter["PacketFilter.cs"] S_PktFilterInfo["PacketFilterInfo.cs"] end L_Program --> L_PluginEntry L_Program --> L_ManifestEntry A_Program --> A_App A_App --> A_Engine A_Engine --> S_Extension A_Engine --> S_MacroMgr A_Engine --> S_HotkeyMgr S_MacroMgr --> S_MacroInv S_HotkeyMgr --> S_HotkeyCmd S_HotkeyMgr --> S_HotkeyCmdAttr S_InPktFilters --> S_PktFilter S_OutPktFilters --> S_PktFilter S_PktFilter --> S_PktFilterInfo ``` **Diagram sources** - [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200) - [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200) - [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200) - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200) - [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200) - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) - [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200) - [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) **Section sources** - [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200) - [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200) - [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) ## Core Components - Extension base class: Defines the contract for plugins to integrate with the host. Implementers typically initialize services, register commands, and subscribe to events. - Macro framework: Provides a registry and invoker for macro commands with typed parameters and validation. - Hotkey system: Allows registering commands bound to key combinations via attributes and a manager. - Packet filters: Incoming and outgoing filter pipelines for intercepting and transforming network messages. - Launcher metadata: Plugin and manifest entries used for discovery and configuration. Key responsibilities: - Discovery and loading of assemblies and plugin types. - Registration of macro commands and hotkey handlers. - Execution context for macros and commands. - Filtering pipeline for network packets. - Lifecycle hooks for initialization and cleanup. **Section sources** - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200) - [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200) - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) - [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200) - [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) ## Architecture Overview The plugin architecture centers on an Extension base type that plugins implement. The host application discovers and loads plugin assemblies, instantiates extensions, and wires them into the macro and hotkey systems. Network traffic is filtered through incoming and outgoing pipelines using filter definitions. ```mermaid classDiagram class Extension { +Initialize() +OnLoad() +OnUnload() +RegisterCommands() +RegisterHotkeys() +RegisterFilters() } class MacroManager { +Register(commandName, handler) +Invoke(name, args) +GetHelp(name) } class MacroInvoker { +Execute(context, command, args) +ValidateParameters(args) } class HotkeyManager { +Register(keyCombination, command) +Unregister(keyCombination) +Dispatch(eventArgs) } class HotkeyCommandAttribute { +Name +Description +RequiresContext } class HotkeyCommand { +Execute(context) +CanExecute(context) bool } class IncomingPacketFilters { +Add(filter) +Process(packet) } class OutgoingPacketFilters { +Add(filter) +Process(packet) } class PacketFilter { +Apply(info) bool +Transform(info) void } class PacketFilterInfo { +Direction +Payload +Metadata } Extension --> MacroManager : "registers" Extension --> HotkeyManager : "registers" Extension --> IncomingPacketFilters : "adds filters" Extension --> OutgoingPacketFilters : "adds filters" MacroManager --> MacroInvoker : "invokes" HotkeyManager --> HotkeyCommand : "dispatches" HotkeyCommand <.. HotkeyCommandAttribute : "annotated" IncomingPacketFilters --> PacketFilter : "uses" OutgoingPacketFilters --> PacketFilter : "uses" PacketFilter --> PacketFilterInfo : "operates on" ``` **Diagram sources** - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200) - [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200) - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) - [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200) - [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200) ## Detailed Component Analysis ### Plugin Discovery and Assembly Loading - The launcher defines metadata structures for plugin entries and manifests, enabling listing and selection of available plugins. - The Avalonia app initializes the engine and triggers extension loading. - Extensions are expected to be discoverable by scanning configured directories or packages and loading assemblies that expose compatible types. ```mermaid sequenceDiagram participant Launcher as "Launcher Program" participant Manifest as "ManifestEntry" participant Entry as "PluginEntry" participant App as "Avalonia App" participant Engine as "Engine" participant Ext as "Extension" Launcher->>Manifest : Load manifest files Launcher->>Entry : Resolve plugin entries Launcher-->>App : Start app with selected plugins App->>Engine : Initialize engine Engine->>Engine : Discover plugin assemblies Engine->>Ext : Instantiate Extension implementations Ext->>Engine : Register commands/hotkeys/filters Engine-->>App : Ready ``` **Diagram sources** - [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200) - [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200) - [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) **Section sources** - [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200) - [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200) - [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) ### Command Registration System (Macros and Hotkeys) - Macro commands are registered via the macro manager and invoked through the macro invoker. Commands can declare parameters and validation rules. - Hotkey commands are annotated with attributes and managed by the hotkey manager, which dispatches key events to registered handlers. ```mermaid sequenceDiagram participant Ext as "Extension" participant MacroMgr as "MacroManager" participant Invoker as "MacroInvoker" participant HKMgr as "HotkeyManager" participant HKCmd as "HotkeyCommand" Ext->>MacroMgr : Register("commandName", handler) Ext->>HKMgr : Register(KeyCombination, HKCmd) Note over MacroMgr,Invoker : Macro invocation flow User->>MacroMgr : Invoke("commandName", args) MacroMgr->>Invoker : Execute(context, "commandName", args) Invoker-->>MacroMgr : Result Note over HKMgr,HKCmd : Hotkey dispatch flow OS->>HKMgr : KeyDown event HKMgr->>HKCmd : CanExecute(context)? HKCmd-->>HKMgr : true/false HKMgr->>HKCmd : Execute(context) ``` **Diagram sources** - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200) - [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200) **Section sources** - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200) - [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200) ### Macro Command Framework: Parameters, Validation, and Execution Context - Parameter parsing: The invoker parses raw arguments into typed parameters based on command declarations. - Validation: Pre-execution checks ensure required parameters are present and valid; errors are reported back to the caller. - Execution context: Provides access to game state, services, and UI threading primitives during command execution. ```mermaid flowchart TD Start(["Macro Invocation"]) --> Parse["Parse Arguments"] Parse --> Validate{"Validation Passed?"} Validate --> |No| Error["Return Error"] Validate --> |Yes| BuildCtx["Build Execution Context"] BuildCtx --> Execute["Execute Command Handler"] Execute --> Post["Post-processing and Logging"] Post --> End(["Result Returned"]) Error --> End ``` **Diagram sources** - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) **Section sources** - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) ### Filter System Architecture: Message Processing and Data Transformation - Incoming and outgoing filter collections manage lists of packet filters. - Each filter implements logic to apply conditions and transform payloads. - Filters operate on filter info objects containing direction, payload, and metadata. ```mermaid sequenceDiagram participant Net as "Network Layer" participant InF as "IncomingPacketFilters" participant OutF as "OutgoingPacketFilters" participant Filt as "PacketFilter" participant Info as "PacketFilterInfo" Net->>InF : OnIncoming(packet) InF->>Filt : Apply(Info) Filt-->>InF : allow/deny InF->>Filt : Transform(Info) if allowed Net->>OutF : OnOutgoing(packet) OutF->>Filt : Apply(Info) Filt-->>OutF : allow/deny OutF->>Filt : Transform(Info) if allowed ``` **Diagram sources** - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) - [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200) - [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200) **Section sources** - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) - [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200) - [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200) ### Plugin Lifecycle Management, Dependency Resolution, and Version Compatibility - Lifecycle: Extensions provide hooks for initialization and unload. The engine coordinates startup order and teardown. - Dependencies: Plugins may declare dependencies on other plugins or core services; the loader resolves and validates these before activation. - Version compatibility: Manifests specify minimum host versions and plugin versions; incompatible combinations are rejected at load time. ```mermaid stateDiagram-v2 [*] --> Discovered Discovered --> ResolvingDependencies : "Resolve deps" ResolvingDependencies --> Loaded : "All deps satisfied" ResolvingDependencies --> Failed : "Missing/incompatible deps" Loaded --> Initialized : "Extension.Initialize()" Initialized --> Running : "Extension.OnLoad()" Running --> Unloading : "Shutdown requested" Unloading --> Unloaded : "Extension.OnUnload()" Unloaded --> [*] Failed --> [*] ``` **Diagram sources** - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) **Section sources** - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) ### Security Considerations: Sandboxing and Permissions - Execution isolation: Prefer running plugin code in isolated contexts where possible to limit access to sensitive APIs. - Permission model: Define explicit capabilities for plugins (e.g., file I/O, network access, UI interaction). Enforce at registration and invocation boundaries. - Input validation: Always validate macro inputs and hotkey-bound actions to prevent injection or unintended side effects. - Resource limits: Cap CPU and memory usage for plugin operations; throttle long-running tasks and enforce timeouts. - Audit and logging: Record plugin actions for diagnostics and compliance. [No sources needed since this section provides general guidance] ## Dependency Analysis The following diagram shows key dependencies between components involved in plugin functionality. ```mermaid graph LR Engine["Engine.cs"] --> Extension["Extension.cs"] Engine --> MacroMgr["MacroManager.cs"] Engine --> HotkeyMgr["HotkeyManager.cs"] MacroMgr --> MacroInv["MacroInvoker.cs"] HotkeyMgr --> HKCmd["HotkeyCommand.cs"] HotkeyMgr --> HKAttr["HotkeyCommandAttribute.cs"] InPkt["IncomingPacketFilters.cs"] --> PktF["PacketFilter.cs"] OutPkt["OutgoingPacketFilters.cs"] --> PktF PktF --> PktInfo["PacketFilterInfo.cs"] Launcher["Program.cs"] --> App["App.axaml.cs"] App --> Engine Launcher --> PluginEntry["PluginEntry.cs"] Launcher --> ManifestEntry["ManifestEntry.cs"] ``` **Diagram sources** - [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200) - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200) - [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200) - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) - [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200) - [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200) - [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200) - [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) **Section sources** - [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200) - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200) - [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200) - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) - [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200) - [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200) - [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200) - [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200) - [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200) - [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200) ## Performance Considerations - Keep filter logic efficient; avoid heavy allocations per packet and batch transformations when possible. - Use asynchronous execution for long-running macro commands to prevent blocking the main thread. - Cache expensive lookups and metadata resolved from manifests or plugin descriptors. - Limit hotkey handler complexity; delegate heavy work to background tasks and marshal results back to UI safely. [No sources needed since this section provides general guidance] ## Security Considerations - Sandbox plugin execution by restricting access to sensitive APIs and resources. - Enforce a permission model that grants only necessary capabilities to each plugin. - Validate all macro parameters and user inputs rigorously. - Monitor resource consumption and enforce timeouts to mitigate denial-of-service risks. - Log plugin activity for auditability and incident response. [No sources needed since this section provides general guidance] ## Troubleshooting Guide Common issues and resolutions: - Plugin not discovered: Verify assembly paths and manifest correctness; ensure the engine’s discovery routine scans the intended directories. - Initialization failures: Check Extension initialization hooks for exceptions; review logs for missing dependencies or version mismatches. - Macro command not found: Confirm registration calls occur during plugin load; verify command names and parameter signatures match invocations. - Hotkey not responding: Ensure hotkey registration uses unique key combinations and that the dispatcher is active; check CanExecute guards. - Filters dropping packets: Inspect filter Apply logic and conditions; add logging around Transform steps to diagnose unexpected behavior. **Section sources** - [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200) - [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200) - [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200) - [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200) - [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200) ## Conclusion The ClassicAssist.Avalonia plugin architecture provides a robust foundation for extending functionality through well-defined contracts. Extensions integrate via the Extension base, register macro commands and hotkey handlers, and participate in network filtering. The launcher and engine coordinate discovery, lifecycle, and compatibility, while security and performance best practices ensure safe and efficient operation. Following the guidelines here will help you build reliable, maintainable plugins that enhance the host application. [No sources needed since this section summarizes without analyzing specific files] ## Appendices ### Guidelines for Developing Custom Plugins and Extensions - Implement the Extension interface and use provided hooks to register commands, hotkeys, and filters. - Declare dependencies and version requirements in your manifest; test against supported host versions. - Validate all inputs and handle errors gracefully; log meaningful diagnostics. - Keep hotkey handlers lightweight; offload heavy work to background tasks. - Design filters to be fast and idempotent; avoid mutating shared state unnecessarily. - Follow the permission model and request only the capabilities your plugin needs. [No sources needed since this section provides general guidance]