Files
Beyhan Oğur d5f52cc3d3 first commit
2026-09-03 04:45:36 +03:00

22 KiB
Raw Permalink Blame History

Extension Points

**Referenced Files in This Document** - [IConfigurableFilter.cs](file://ClassicAssist.Shared/Data/Filters/IConfigurableFilter.cs) - [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs) - [FilterOptionsAttribute.cs](file://ClassicAssist.Shared/Data/Filters/FilterOptionsAttribute.cs) - [ClilocFilter.cs](file://ClassicAssist.Shared/Data/Filters/ClilocFilter.cs) - [RepeatedMessagesFilter.cs](file://ClassicAssist.Shared/Data/Filters/RepeatedMessagesFilter.cs) - [DynamicFilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/DynamicFilterEntry.cs) - [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs) - [HotkeyCommandAttribute.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs) - [HotkeyCommand.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs) - [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs) - [HotkeyEntry.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyEntry.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) - [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs) - [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs) - [Program.cs](file://ClassicAssist.Avalonia/Program.cs) - [PluginEntry.cs](file://ClassicAssist.Launcher/PluginEntry.cs) - [ShardManager.cs](file://ClassicAssist.Launcher/ShardManager.cs) - [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs) - [HotkeysTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/HotkeysTabViewModel.cs) - [ClilocFilterConfigureWindow.xaml.cs](file://ClassicAssist.Avalonia/Views/Filters/ClilocFilterConfigureWindow.xaml.cs) - [RepeatedMessagesFilterConfigureWindow.xaml.cs](file://ClassicAssist.Avalonia/Views/Filters/RepeatedMessagesFilterConfigureWindow.xaml.cs)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendices

Introduction

This document explains how to extend ClassicAssist.Avalonia using its extension points. It focuses on:

  • Filter system interfaces for custom message filters (IConfigurableFilter and FilterEntry)
  • Hotkey command extension points via HotkeyCommandAttribute
  • Plugin architecture guidelines including assembly loading, dependency injection, and lifecycle management
  • Configuration schemas, validation rules, and testing strategies
  • Security considerations, performance impact, and distribution methods

The goal is to enable developers to implement custom filters, hotkey commands, and UI extensions that integrate cleanly with the application’s runtime and configuration model.

Project Structure

The extension points are primarily defined in the shared layer and consumed by the Avalonia UI and launcher components:

  • Shared filter interfaces and attributes under Data/Filters
  • Hotkey command attribute and manager under Data/Hotkeys
  • Packet filtering pipeline under UO/Network
  • Avalonia app bootstrap and engine initialization under ClassicAssist.Avalonia
  • Launcher plugin entry and shard management under ClassicAssist.Launcher
graph TB
subgraph "Shared"
FIF["IConfigurableFilter.cs"]
FE["FilterEntry.cs"]
FOA["FilterOptionsAttribute.cs"]
HCA["HotkeyCommandAttribute.cs"]
HCM["HotkeyManager.cs"]
IPF["IncomingPacketFilters.cs"]
OPF["OutgoingPacketFilters.cs"]
PF["PacketFilter.cs"]
end
subgraph "Avalonia"
APP["App.axaml.cs"]
ENG["Engine.cs"]
PRG["Program.cs"]
CFW["ClilocFilterConfigureWindow.xaml.cs"]
RMFW["RepeatedMessagesFilterConfigureWindow.xaml.cs"]
end
subgraph "Launcher"
PLE["PluginEntry.cs"]
SM["ShardManager.cs"]
end
FIF --> FE
FOA --> FE
HCA --> HCM
IPF --> PF
OPF --> PF
APP --> ENG
PRG --> APP
PLE --> SM
CFW --> FE
RMFW --> FE

Diagram sources

Section sources

Core Components

  • IConfigurableFilter: Interface for creating custom message filters that can be configured through the UI.
  • FilterEntry: Base type or container used to represent a filter instance and its configuration state.
  • FilterOptionsAttribute: Attribute-driven metadata to describe filter options for UI binding and validation.
  • HotkeyCommandAttribute: Attribute to register a class as a hotkey command, enabling discovery and registration into the hotkey system.
  • HotkeyManager: Central registry and dispatcher for hotkey commands.
  • IncomingPacketFilters / OutgoingPacketFilters: Pipeline hooks for intercepting network packets.
  • PacketFilter: Core packet filtering infrastructure used by incoming/outgoing pipelines.

These components form the foundation for extending message filtering and keyboard shortcuts.

Section sources

Architecture Overview

The extension architecture separates concerns across layers:

  • Shared layer defines contracts (interfaces, attributes, base types).
  • Avalonia layer provides UI integration and bootstrapping.
  • Launcher handles plugin discovery and lifecycle.
sequenceDiagram
participant Boot as "Program.cs"
participant App as "App.axaml.cs"
participant Engine as "Engine.cs"
participant Filters as "Filters.cs"
participant InPkt as "IncomingPacketFilters.cs"
participant OutPkt as "OutgoingPacketFilters.cs"
participant PktF as "PacketFilter.cs"
Boot->>App : Initialize application
App->>Engine : Start engine and services
Engine->>Filters : Register built-in and discovered filters
Engine->>InPkt : Attach incoming packet pipeline
Engine->>OutPkt : Attach outgoing packet pipeline
InPkt->>PktF : Apply filters to incoming packets
OutPkt->>PktF : Apply filters to outgoing packets
Note over InPkt,OutPkt : Custom filters implement IConfigurableFilter<br/>and are registered via FilterEntry

Diagram sources

Detailed Component Analysis

Filter System: IConfigurableFilter and FilterEntry

Custom message filters should implement IConfigurableFilter and be represented via FilterEntry. The FilterOptionsAttribute enables declarative configuration UI generation and validation.

classDiagram
class IConfigurableFilter {
+string Name
+bool IsEnabled
+void Configure()
+bool Evaluate(message) bool
}
class FilterEntry {
+string Id
+string Name
+bool Enabled
+object Options
+void Save()
+void Load()
}
class FilterOptionsAttribute {
+string DisplayName
+string Description
+Type ValueType
+object DefaultValue
}
IConfigurableFilter <.. FilterEntry : "implemented by"
FilterEntry --> FilterOptionsAttribute : "uses for schema"

Key implementation patterns:

  • Implement IConfigurableFilter to define evaluation logic and configuration behavior.
  • Use FilterEntry to persist and bind filter state to UI.
  • Annotate configuration properties with FilterOptionsAttribute to drive UI and validation.

Example references:

  • Built-in configurable filters demonstrate usage patterns:
    • ClilocFilter
    • RepeatedMessagesFilter

UI configuration windows:

  • ClilocFilterConfigureWindow
  • RepeatedMessagesFilterConfigureWindow

Diagram sources

Section sources

Hotkey Command Extension Points: HotkeyCommandAttribute

To add a new hotkey command:

  • Decorate your command class with HotkeyCommandAttribute.
  • Ensure the class adheres to the expected contract recognized by HotkeyManager.
  • The manager will discover and register the command during startup.
sequenceDiagram
participant Boot as "Program.cs"
participant App as "App.axaml.cs"
participant Engine as "Engine.cs"
participant HM as "HotkeyManager.cs"
participant Cmd as "YourHotkeyCommand.cs"
Boot->>App : Initialize
App->>Engine : Start services
Engine->>HM : Discover commands via reflection
HM-->>Cmd : Instantiate decorated classes
HM->>HM : Register command mappings
Note over HM,Cmd : Commands are later invoked when user presses bound keys

Diagram sources

Section sources

Plugin Architecture Guidelines

Guidelines for building plugins:

  • Assembly loading: Place plugin assemblies in the designated directory; the launcher scans for entries compatible with the plugin manifest.
  • Dependency injection: Use constructor injection where possible; rely on shared services exposed by the engine.
  • Lifecycle management: Implement initialization and cleanup hooks if needed; ensure thread-safety for background operations.
  • Manifest and metadata: Provide required metadata so the launcher can enumerate and load your plugin safely.

Relevant components:

  • PluginEntry: Represents a plugin manifest entry.
  • ShardManager: Manages shards and may coordinate plugin loading contexts.
flowchart TD
Start(["Application Start"]) --> Scan["Scan Plugins Directory"]
Scan --> LoadManifest["Load PluginEntry Metadata"]
LoadManifest --> Validate{"Valid Manifest?"}
Validate --> |No| Skip["Skip Plugin"]
Validate --> |Yes| LoadAsm["Load Assembly Safely"]
LoadAsm --> DI["Resolve Dependencies"]
DI --> Init["Initialize Plugin"]
Init --> Run["Run During Session"]
Run --> Cleanup["Cleanup on Shutdown"]
Cleanup --> End(["Exit"])
Skip --> End

[No sources needed since this diagram shows conceptual workflow, not actual code structure]

Section sources

Network Filtering Integration

Custom filters can participate in the packet filtering pipeline:

  • IncomingPacketFilters and OutgoingPacketFilters provide hooks to apply filters to network traffic.
  • PacketFilter encapsulates core filtering logic and conditions.
flowchart TD
InStart(["Incoming Packet"]) --> ApplyIn["Apply Incoming Filters"]
ApplyIn --> DecisionIn{"Filtered?"}
DecisionIn --> |Yes| DropIn["Drop Packet"]
DecisionIn --> |No| DispatchIn["Dispatch to Handlers"]
OutStart(["Outgoing Packet"]) --> ApplyOut["Apply Outgoing Filters"]
ApplyOut --> DecisionOut{"Filtered?"}
DecisionOut --> |Yes| DropOut["Drop Packet"]
DecisionOut --> |No| SendOut["Send Over Network"]

Diagram sources

Section sources

Dependency Analysis

High-level dependencies among extension points:

  • Filters depend on IConfigurableFilter and FilterEntry for configuration and persistence.
  • Hotkey commands depend on HotkeyCommandAttribute and HotkeyManager for discovery and dispatch.
  • Network filters depend on IncomingPacketFilters and OutgoingPacketFilters to integrate with the packet pipeline.
graph LR
ICF["IConfigurableFilter.cs"] --> FE["FilterEntry.cs"]
FOA["FilterOptionsAttribute.cs"] --> FE
HCA["HotkeyCommandAttribute.cs"] --> HCM["HotkeyManager.cs"]
INPF["IncomingPacketFilters.cs"] --> PF["PacketFilter.cs"]
OUTPF["OutgoingPacketFilters.cs"] --> PF

Diagram sources

Section sources

Performance Considerations

  • Keep filter evaluation logic lightweight; avoid heavy allocations and blocking I/O inside hot paths.
  • Prefer early-exit conditions to minimize processing overhead.
  • Batch operations where possible and avoid synchronous UI calls from background threads.
  • For hotkey commands, ensure quick execution; offload long-running tasks to background threads and marshal results back to the UI thread.
  • Be mindful of memory retention in filter state; release resources promptly.

[No sources needed since this section provides general guidance]

Troubleshooting Guide

Common issues and resolutions:

  • Filters not appearing in UI:
    • Verify IConfigurableFilter implementation and FilterEntry registration.
    • Check FilterOptionsAttribute usage for correct property exposure.
  • Hotkey commands not firing:
    • Confirm HotkeyCommandAttribute decoration and proper registration via HotkeyManager.
    • Ensure no conflicts with existing key bindings.
  • Network filters not applied:
    • Validate integration with IncomingPacketFilters and OutgoingPacketFilters.
    • Inspect PacketFilter conditions and order of application.

Validation and diagnostics:

  • Use unit tests to validate filter logic and hotkey command behavior.
  • Add logging around filter evaluation and command invocation to trace issues.

Section sources

Conclusion

By implementing IConfigurableFilter and leveraging FilterEntry and FilterOptionsAttribute, you can create robust, configurable message filters. Using HotkeyCommandAttribute and HotkeyManager, you can register custom keyboard shortcuts seamlessly. Follow the plugin architecture guidelines for safe assembly loading, dependency resolution, and lifecycle management. Adhering to performance best practices and security considerations ensures reliable and efficient extensions.

[No sources needed since this section summarizes without analyzing specific files]

Appendices

Configuration Schema and Validation Rules

  • FilterOptionsAttribute drives the schema for filter options.
  • Define display names, descriptions, value types, and defaults to guide UI rendering and validation.
  • Persist options via FilterEntry to maintain user preferences across sessions.

Section sources

Testing Strategies

  • Unit test filter evaluation logic with representative messages.
  • Mock HotkeyManager interactions to verify command registration and invocation.
  • Simulate packet flows to validate network filter behavior.

Section sources

Security Considerations

  • Validate all inputs in filters and commands to prevent injection or malformed data issues.
  • Restrict file system and network access within plugins to necessary scopes.
  • Avoid executing arbitrary code loaded from untrusted sources; enforce manifest checks and signature verification where applicable.

[No sources needed since this section provides general guidance]

Distribution Methods for Plugins

  • Package plugin assemblies with required dependencies.
  • Include a manifest describing plugin metadata and capabilities.
  • Distribute via official channels or trusted repositories; ensure users place plugins in the correct directory for discovery.

Section sources