first commit

This commit is contained in:
Beyhan Oğur
2026-09-03 04:45:36 +03:00
commit d5f52cc3d3
1038 changed files with 169579 additions and 0 deletions
@@ -0,0 +1,459 @@
# Architecture Overview
<cite>
**Referenced Files in This Document**
- [README.md](file://README.md)
- [ClassicAssist.Shared/Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [ClassicAssist.Avalonia/Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [ClassicAssist.Avalonia/App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [ClassicAssist.Launcher/MainViewModel.cs](file://ClassicAssist.Launcher/MainViewModel.cs)
- [ClassicAssist.Shared/UO/Network/PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [ClassicAssist.Shared/UO/Objects/Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [ClassicAssist.Shared/Data/Macros/MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [ClassicAssist.Avalonia/Views/MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [ClassicAssist.Avalonia/AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [ClassicAssist/WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [ClassicAssist.Shared/IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
</cite>
## 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. [Troubleshooting Guide](#troubleshooting-guide)
9. [Conclusion](#conclusion)
## Introduction
ClassicAssist.Avalonia is a cross-platform Ultima Online game assistant application built using the Avalonia UI framework. The system follows a layered architecture pattern that separates concerns between the user interface layer, shared business logic, and platform-specific implementations. This design enables code reuse across multiple UI frameworks (WPF and Avalonia) while maintaining clean separation of responsibilities.
The application provides comprehensive game automation features including macro scripting, agent management, filtering systems, and real-time packet processing for Ultima Online gameplay enhancement.
## Project Structure
The ClassicAssist.Avalonia solution follows a modular architecture with clear separation between different functional areas:
```mermaid
graph TB
subgraph "UI Layer"
A[ClassicAssist.Avalonia]
B[ClassicAssist.WPF]
C[ClassicAssist.Launcher]
end
subgraph "Shared Core"
D[ClassicAssist.Shared]
E[ClassicAssist.Tests]
end
subgraph "External Dependencies"
F[UO Game Engine]
G[Plugin System]
end
A --> D
B --> D
C --> D
D --> F
D --> G
```
**Diagram sources**
- [ClassicAssist.Avalonia/Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [ClassicAssist.Shared/Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [ClassicAssist.Launcher/MainViewModel.cs](file://ClassicAssist.Launcher/MainViewModel.cs)
The project structure demonstrates a clean separation where:
- **ClassicAssist.Shared**: Contains all business logic, data models, and core functionality
- **ClassicAssist.Avalonia**: Avalonia-specific UI implementation
- **ClassicAssist.WPF**: WPF-specific UI implementation
- **ClassicAssist.Launcher**: Application launcher and configuration management
**Section sources**
- [README.md](file://README.md)
- [ClassicAssist.Avalonia/Program.cs](file://ClassicAssist.Avalonia/Program.cs)
## Core Components
### Shared Library Architecture
The ClassicAssist.Shared library serves as the foundation containing all reusable business logic:
#### Network Processing Pipeline
The network subsystem handles Ultima Online protocol communication through a sophisticated packet processing pipeline:
```mermaid
sequenceDiagram
participant Game as "UO Game Client"
participant Network as "PacketHandler"
participant Filters as "PacketFilters"
participant Handlers as "PacketHandlers"
participant UI as "UI Layer"
Game->>Network : Incoming Packet
Network->>Filters : Apply Filters
Filters-->>Network : Filtered Data
Network->>Handlers : Route to Handler
Handlers->>Handlers : Process Logic
Handlers->>UI : Update State
UI-->>Game : Response Actions
```
**Diagram sources**
- [ClassicAssist.Shared/UO/Network/PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [ClassicAssist.Shared/UO/Objects/Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
#### Plugin-Based Extensibility Model
The system implements a robust plugin architecture allowing third-party extensions:
```mermaid
classDiagram
class PluginBase {
<<abstract>>
+string Name
+string Version
+Initialize() void
+Execute(context) object
+Dispose() void
}
class MacroCommand {
+string CommandName
+string Description
+Execute(parameters) object
}
class AgentPlugin {
+AgentType Type
+ConfigureDialog() Window
+ProcessLogic() void
}
class FilterPlugin {
+FilterCriteria Criteria
+ApplyFilter(data) bool
}
PluginBase <|-- MacroCommand
PluginBase <|-- AgentPlugin
PluginBase <|-- FilterPlugin
```
**Diagram sources**
- [ClassicAssist.Shared/Data/Macros/MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
**Section sources**
- [ClassicAssist.Shared/Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [ClassicAssist.Shared/UO/Network/PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
## Architecture Overview
### High-Level System Architecture
The ClassicAssist.Avalonia system follows a multi-layered architecture pattern:
```mermaid
graph TB
subgraph "Presentation Layer"
A[Avalonia UI]
B[WPF UI]
C[Launcher UI]
end
subgraph "Application Layer"
D[Main Application Controller]
E[Window Management]
F[State Management]
end
subgraph "Business Logic Layer"
G[Shared Business Logic]
H[Game Engine Integration]
I[Plugin Framework]
end
subgraph "Data Layer"
J[Configuration Storage]
K[Game Data Cache]
L[Network Communication]
end
A --> D
B --> D
C --> D
D --> G
D --> H
D --> I
G --> J
H --> K
H --> L
```
**Diagram sources**
- [ClassicAssist.Avalonia/App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [ClassicAssist.Shared/Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Cross-Platform UI Abstraction
The system achieves cross-platform compatibility through abstraction layers:
```mermaid
classDiagram
class IDispatcher {
<<interface>>
+Invoke(action) void
+BeginInvoke(action) void
+Synchronize(context) void
}
class AvaloniaDispatcher {
+Invoke(action) void
+BeginInvoke(action) void
+Synchronize(context) void
}
class WPFDispatcher {
+Invoke(action) void
+BeginInvoke(action) void
+Synchronize(context) void
}
class IUIInvoker {
<<interface>>
+ShowMessageBox(message) void
+OpenFileDialog() string
+SaveFileDialog() string
}
class AvaloniaUIInvoker {
+ShowMessageBox(message) void
+OpenFileDialog() string
+SaveFileDialog() string
}
class WPFUIInvoker {
+ShowMessageBox(message) void
+OpenFileDialog() string
+SaveFileDialog() string
}
IDispatcher <|.. AvaloniaDispatcher
IDispatcher <|.. WPFDispatcher
IUIInvoker <|.. AvaloniaUIInvoker
IUIInvoker <|.. WPFUIInvoker
```
**Diagram sources**
- [ClassicAssist.Shared/IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [ClassicAssist.Avalonia/AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [ClassicAssist/WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
**Section sources**
- [ClassicAssist.Avalonia/App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [ClassicAssist.Avalonia/AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
## Detailed Component Analysis
### Main Application Flow
The application initialization and main flow follows a structured startup sequence:
```mermaid
sequenceDiagram
participant Program as "Program.Main"
participant App as "Avalonia Application"
participant Engine as "Shared Engine"
participant MainWindow as "Main Window"
participant ViewModel as "Main Window ViewModel"
Program->>App : Initialize Application
App->>Engine : Load Shared Engine
Engine->>Engine : Initialize Plugins
Engine->>Engine : Setup Network
App->>MainWindow : Create Main Window
MainWindow->>ViewModel : Bind ViewModel
ViewModel->>Engine : Request Initial Data
Engine-->>ViewModel : Provide Data
ViewModel-->>MainWindow : Update UI
```
**Diagram sources**
- [ClassicAssist.Avalonia/Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [ClassicAssist.Avalonia/App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [ClassicAssist.Shared/Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Data Flow Architecture
The system implements a unidirectional data flow pattern ensuring predictable state updates:
```mermaid
flowchart TD
A[Network Packet] --> B[Packet Handler]
B --> C{Filter Check}
C --> |Pass| D[Business Logic Processor]
C --> |Blocked| E[Discard]
D --> F[State Manager]
F --> G[ViewModel Update]
G --> H[UI Binding]
H --> I[Visual Update]
J[User Action] --> K[Command Handler]
K --> L[Business Logic]
L --> M[Network Outgoing]
M --> N[Game Server]
```
**Diagram sources**
- [ClassicAssist.Shared/UO/Network/PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
### Plugin System Implementation
The extensible plugin architecture supports multiple extension points:
```mermaid
classDiagram
class PluginManager {
-Dictionary~string,PluginBase~ plugins
+LoadPlugins(path) void
+GetPlugin(name) PluginBase
+ExecutePlugin(name, context) object
+UnloadPlugin(name) void
}
class PluginBase {
<<abstract>>
#string name
#string version
#string description
+virtual Initialize() void
+virtual Execute(context) object
+virtual Dispose() void
}
class MacroPlugin {
+MacroEntry[] macros
+RegisterCommands() void
+ExecuteMacro(name) void
}
class AgentPlugin {
+IAgent[] agents
+StartAgents() void
+StopAgents() void
}
PluginManager --> PluginBase : manages
PluginBase <|-- MacroPlugin
PluginBase <|-- AgentPlugin
```
**Diagram sources**
- [ClassicAssist.Shared/Data/Macros/MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
**Section sources**
- [ClassicAssist.Avalonia/Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [ClassicAssist.Avalonia/Views/MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
## Dependency Analysis
### Component Coupling and Cohesion
The system demonstrates high cohesion within modules and loose coupling between components:
```mermaid
graph TB
subgraph "High Cohesion Modules"
A[Network Module]
B[UI Module]
C[Plugin Module]
D[Data Module]
end
subgraph "Low Coupling Interfaces"
E[IDispatcher]
F[IUIInvoker]
G[IPlugin]
H[IConfigProvider]
end
A --> E
B --> F
C --> G
D --> H
```
### External Dependencies Management
The system manages external dependencies through NuGet packages and assembly references:
```mermaid
graph LR
subgraph "Core Dependencies"
A[Avalonia Framework]
B[Newtonsoft.Json]
C[Microsoft.CSharp]
end
subgraph "Game Integration"
D[UO Protocol Parser]
E[Memory Access Libraries]
end
subgraph "UI Extensions"
F[Avalonia.Controls]
G[Avalonia.Themes]
end
A --> F
A --> G
B --> C
D --> E
```
**Diagram sources**
- [ClassicAssist.Avalonia/ClassicAssist.Avalonia.csproj](file://ClassicAssist.Avalonia/ClassicAssist.Avalonia.csproj)
- [ClassicAssist.Shared/ClassicAssist.Shared.csproj](file://ClassicAssist.Shared/ClassicAssist.Shared.csproj)
**Section sources**
- [ClassicAssist.Shared/Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [ClassicAssist.Avalonia/Program.cs](file://ClassicAssist.Avalonia/Program.cs)
## Performance Considerations
### Memory Management and Optimization
The system implements several performance optimization strategies:
- **Object Pooling**: Reusable objects for frequently created instances
- **Lazy Loading**: Deferred loading of heavy resources
- **Background Processing**: Asynchronous operations for non-blocking UI
- **Event Aggregation**: Efficient event handling patterns
### Threading Model
The application uses a single-threaded UI model with background workers:
```mermaid
stateDiagram-v2
[*] --> Idle
Idle --> Initializing : "Application Start"
Initializing --> Running : "Engine Ready"
Running --> Paused : "Pause Request"
Paused --> Running : "Resume Request"
Running --> Stopping : "Shutdown"
Stopping --> [*] : "Cleanup Complete"
```
## Troubleshooting Guide
### Common Issues and Solutions
#### Network Connectivity Problems
- Verify Ultima Online client connection status
- Check firewall settings for port access
- Validate packet filter configurations
#### UI Rendering Issues
- Ensure proper dispatcher usage for thread safety
- Verify Avalonia theme resource loading
- Check for memory leaks in custom controls
#### Plugin Loading Failures
- Validate plugin assembly signatures
- Check dependency version compatibility
- Review plugin manifest files
**Section sources**
- [ClassicAssist.Shared/Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [ClassicAssist.Avalonia/App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
## Conclusion
ClassicAssist.Avalonia demonstrates a well-architected cross-platform game assistant application that successfully balances code reuse, maintainability, and extensibility. The layered architecture with clear separation of concerns enables efficient development across multiple UI frameworks while providing a robust foundation for plugin-based extensions.
The system's design principles emphasize:
- **Separation of Concerns**: Clear boundaries between UI, business logic, and data layers
- **Cross-Platform Compatibility**: Abstracted interfaces enabling multiple UI implementations
- **Extensibility**: Plugin architecture supporting third-party enhancements
- **Performance**: Optimized data flow and memory management strategies
This architectural approach ensures long-term maintainability while providing a solid foundation for future feature additions and platform support expansion.
@@ -0,0 +1,424 @@
# Core Concepts
<cite>
**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)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
</cite>
## 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. [Troubleshooting Guide](#troubleshooting-guide)
9. [Conclusion](#conclusion)
## Introduction
This document explains the core concepts and architecture of ClassicAssist.Avalonia, focusing on:
- MVVM implementation across the Avalonia UI layer
- The Engine class as the central orchestrator for lifecycle, events, and component initialization
- Dispatcher pattern and UI invoker abstraction for cross-thread UI updates
- Plugin architecture enabling extensibility via macro commands, agents, and filters
- Network packet handling system and its relationship with game entities
- Cross-platform considerations specific to Avalonia
- Performance optimization strategies
## Project Structure
The solution is organized into multiple projects:
- ClassicAssist.Avalonia: Avalonia-based UI application entry point, platform-specific dispatcher and UI invoker, and views
- ClassicAssist.Shared: Shared business logic, data models, network layer, macros, hotkeys, chat, and MVVM base classes
- ClassicAssist (WPF): Legacy WPF UI project retained for compatibility
- ClassicAssist.Launcher: Launcher application for shard selection and profile management
- Tests and utilities under separate projects
```mermaid
graph TB
subgraph "Avalonia UI"
A_Program["Program.cs"]
A_App["App.axaml.cs"]
A_Engine["Engine.cs"]
A_Dispatcher["AvaloniaDispatcher.cs"]
A_Invoker["AvaloniaUIInvoker.cs"]
A_MainView["Views/MainWindow.axaml.cs"]
end
subgraph "Shared Core"
S_VM_Base["BaseViewModel.cs"]
S_VM_Main["MainWindowViewModel.cs"]
S_IDisp["IDispatcher.cs"]
S_UIInv["IUIInvoker.cs"]
S_MacroMgr["MacroManager.cs"]
S_HotkeyMgr["HotkeyManager.cs"]
S_ChatMgr["ChatManager.cs"]
S_InPkt["IncomingPacketHandlers.cs"]
S_OutPkt["OutgoingPacketHandlers.cs"]
S_PktHdlr["PacketHandler.cs"]
S_Entity["Entity.cs"]
S_Mobile["Mobile.cs"]
S_Item["Item.cs"]
end
A_Program --> A_App
A_App --> A_Engine
A_Engine --> A_Dispatcher
A_Engine --> A_Invoker
A_MainView --> S_VM_Main
S_VM_Main --> S_VM_Base
A_Engine --> S_MacroMgr
A_Engine --> S_HotkeyMgr
A_Engine --> S_ChatMgr
A_Engine --> S_InPkt
A_Engine --> S_OutPkt
A_Engine --> S_PktHdlr
S_InPkt --> S_Entity
S_OutPkt --> S_Entity
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
## Core Components
- Engine (Avalonia): Central orchestrator that initializes subsystems, wires event handlers, manages lifecycle, and coordinates UI and network layers.
- AvaloniaDispatcher: Implements IDispatcher for Avalonia, marshaling work onto the UI thread.
- AvaloniaUIInvoker: Implements IUIInvoker to provide platform-independent UI operations (e.g., message boxes).
- MVVM Layer: Views (Avalonia XAML/Code-behind) bind to ViewModels; ViewModels inherit from BaseViewModel and expose state and commands.
- Network Layer: Packet handlers process incoming/outgoing packets and update shared entity collections.
- Extensibility: MacroManager, HotkeyManager, and ChatManager provide extension points for commands, hotkeys, and chat integrations.
Key responsibilities:
- Lifecycle: Application startup, configuration loading, plugin discovery, and graceful shutdown.
- Event-driven communication: Decouples components via events and managers.
- Cross-thread safety: Ensures UI updates occur on the UI thread using the dispatcher.
- Platform abstraction: Uses interfaces for UI invocations to remain platform-neutral.
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
## Architecture Overview
The system follows a layered architecture:
- Presentation Layer (Avalonia): Views and ViewModels implement MVVM.
- Core Layer (Shared): Business logic, data models, network processing, and managers.
- Infrastructure Layer: Platform-specific implementations for dispatcher and UI invoker.
```mermaid
sequenceDiagram
participant App as "App.axaml.cs"
participant Engine as "Engine.cs"
participant Disp as "AvaloniaDispatcher.cs"
participant Inv as "AvaloniaUIInvoker.cs"
participant VM as "MainWindowViewModel.cs"
participant NetIn as "IncomingPacketHandlers.cs"
participant NetOut as "OutgoingPacketHandlers.cs"
participant Pkt as "PacketHandler.cs"
participant Ent as "Entity.cs"
App->>Engine : Initialize()
Engine->>Disp : Register dispatcher
Engine->>Inv : Register UI invoker
Engine->>NetIn : Subscribe to incoming packets
Engine->>NetOut : Subscribe to outgoing packets
Engine->>VM : Create main window view model
Note over Engine,VM : Bind View to ViewModel
NetIn->>Pkt : Handle incoming packet
Pkt->>Ent : Update entity state
Pkt-->>VM : Notify changes (events or properties)
VM->>Disp : Invoke UI update on UI thread
VM->>Inv : Show dialog / message if needed
```
**Diagram sources**
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
## Detailed Component Analysis
### MVVM Implementation Across Avalonia UI
- Views: Avalonia XAML files define layout and bindings; code-behind handles minimal UI logic.
- ViewModels: Expose observable properties and commands; inherit from BaseViewModel to support change notification.
- Data Binding: Views bind to ViewModels; updates propagate through property change notifications.
- Commands: User actions are bound to commands in ViewModels, keeping UI logic testable and decoupled.
```mermaid
classDiagram
class BaseViewModel {
+NotifyPropertyChanged(propertyName)
+RaiseEvent(eventArgs)
}
class MainWindowViewModel {
+Title
+OpenOptions()
+CloseWindow()
}
class MainWindowView {
+InitializeComponent()
+DataContext
}
MainWindowViewModel --|> BaseViewModel : "inherits"
MainWindowView --> MainWindowViewModel : "binds to"
```
**Diagram sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
### Engine Class: Central Orchestrator
Responsibilities:
- Initializes subsystems (network, macros, hotkeys, chat).
- Registers event handlers for incoming/outgoing packets.
- Creates and configures ViewModels and Views.
- Manages application lifecycle and resource cleanup.
```mermaid
flowchart TD
Start([Application Startup]) --> InitEngine["Engine.Initialize()"]
InitEngine --> LoadConfig["Load Configuration"]
LoadConfig --> RegisterDispatchers["Register Dispatcher & UI Invoker"]
RegisterDispatchers --> SubscribeNetwork["Subscribe Packet Handlers"]
SubscribeNetwork --> CreateUI["Create Main Window & ViewModel"]
CreateUI --> RunLoop["Run Message Loop"]
RunLoop --> Shutdown["Graceful Shutdown"]
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
### Dispatcher Pattern and UI Invoker Abstraction
- IDispatcher: Interface defining cross-thread execution primitives.
- AvaloniaDispatcher: Concrete implementation for Avalonia, ensuring UI updates run on the UI thread.
- IUIInvoker: Interface abstracting UI operations like showing dialogs.
- AvaloniaUIInvoker: Concrete implementation providing Avalonia-specific UI calls.
```mermaid
classDiagram
class IDispatcher {
+Invoke(action)
+BeginInvoke(action)
}
class AvaloniaDispatcher {
+Invoke(action)
+BeginInvoke(action)
}
class IUIInvoker {
+ShowMessage(title, message)
+ShowDialog(window)
}
class AvaloniaUIInvoker {
+ShowMessage(title, message)
+ShowDialog(window)
}
AvaloniaDispatcher ..|> IDispatcher : "implements"
AvaloniaUIInvoker ..|> IUIInvoker : "implements"
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
### Plugin Architecture: Macros, Agents, and Filters
- MacroManager: Loads and executes macro commands; supports dynamic command registration.
- HotkeyManager: Binds keyboard shortcuts to commands; integrates with UI and background threads.
- ChatManager: Provides chat integration and message routing.
- Extensibility: New macro commands, agent behaviors, and filters can be added without modifying core logic.
```mermaid
sequenceDiagram
participant User as "User"
participant HM as "HotkeyManager.cs"
participant MM as "MacroManager.cs"
participant CM as "ChatManager.cs"
participant VM as "MainWindowViewModel.cs"
User->>HM : Press hotkey
HM->>MM : Execute macro command
MM->>CM : Route chat action if needed
MM-->>VM : Update UI state via events
VM->>VM : Refresh bindings
```
**Diagram sources**
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
**Section sources**
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
### Network Layer: Packet Handling and Game Entities
- IncomingPacketHandlers: Processes server-to-client packets and updates entity collections.
- OutgoingPacketHandlers: Handles client-to-server packets and triggers actions.
- PacketHandler: Central registry and dispatch for packet types.
- Entity Model: Base class for game objects; Mobile and Item extend it to represent characters and items.
```mermaid
flowchart TD
InPkt["IncomingPacketHandlers.cs"] --> PktHdlr["PacketHandler.cs"]
PktHdlr --> UpdateEntities["Update Entity State"]
UpdateEntities --> EntityModel["Entity.cs / Mobile.cs / Item.cs"]
OutPkt["OutgoingPacketHandlers.cs"] --> PktHdlr
PktHdlr --> SendAction["Send Action to Server"]
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
## Dependency Analysis
High-level dependencies:
- Avalonia UI depends on Shared ViewModels and Managers.
- Engine depends on Dispatcher and UI Invoker abstractions.
- Network layer depends on Entity models and provides events to ViewModels.
```mermaid
graph LR
A_Engine["Engine.cs"] --> A_Dispatcher["AvaloniaDispatcher.cs"]
A_Engine --> A_Invoker["AvaloniaUIInvoker.cs"]
A_Engine --> S_MacroMgr["MacroManager.cs"]
A_Engine --> S_HotkeyMgr["HotkeyManager.cs"]
A_Engine --> S_ChatMgr["ChatManager.cs"]
A_Engine --> S_InPkt["IncomingPacketHandlers.cs"]
A_Engine --> S_OutPkt["OutgoingPacketHandlers.cs"]
S_InPkt --> S_Entity["Entity.cs"]
S_OutPkt --> S_Entity
A_MainView["MainWindow.axaml.cs"] --> S_VM_Main["MainWindowViewModel.cs"]
S_VM_Main --> S_VM_Base["BaseViewModel.cs"]
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
## Performance Considerations
- Minimize UI thread work: Use dispatcher to batch updates and avoid frequent property changes.
- Efficient packet processing: Keep handlers lightweight; defer heavy computations to background tasks.
- Entity collection updates: Coalesce updates to reduce binding churn.
- Resource management: Dispose resources during shutdown; avoid memory leaks in event subscriptions.
- Cross-platform rendering: Prefer vector graphics and reusable styles to improve performance on different platforms.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- UI not updating: Ensure UI updates are dispatched on the UI thread using the dispatcher.
- Cross-thread exceptions: Verify all UI invocations go through the UI invoker abstraction.
- Packet handling delays: Check for blocking operations in packet handlers; offload to background threads where appropriate.
- Macro command failures: Validate command registration and parameter parsing; inspect logs for errors.
**Section sources**
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
## Conclusion
ClassicAssist.Avalonia implements a robust MVVM architecture with clear separation between UI and core logic. The Engine orchestrates lifecycle and subsystems, while the dispatcher and UI invoker ensure cross-thread safety and platform independence. The network layer processes packets efficiently and updates shared entities, which are consumed by ViewModels for reactive UI updates. Extensibility is achieved through macro commands, hotkeys, and chat integrations. Following the outlined performance and troubleshooting practices will help maintain a responsive and reliable application across platforms.
@@ -0,0 +1,339 @@
# Engine Lifecycle Management
<cite>
**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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
</cite>
## 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. [Troubleshooting Guide](#troubleshooting-guide)
9. [Conclusion](#conclusion)
## Introduction
This document explains the lifecycle management of the Engine class in ClassicAssist.Avalonia, focusing on its role as the central orchestrator for application startup, subsystem initialization, and graceful shutdown. It also documents the event-driven communication model that coordinates network handlers, macro system, agents, and UI updates; the plugin loading mechanism used to discover and initialize extensions; and the thread management strategy for asynchronous operations and cross-thread UI updates. Finally, it provides examples of custom engine extension points and demonstrates how to integrate new features into the engine lifecycle.
## Project Structure
The Avalonia-based entry point initializes the UI framework and then starts the Engine, which is responsible for bootstrapping core services, loading plugins, and managing runtime events. The shared Engine implementation defines the common lifecycle hooks and abstractions for dispatching work across threads and UI invocations.
```mermaid
graph TB
Program["Program.cs<br/>Entry point"] --> App["App.axaml.cs<br/>Application bootstrap"]
App --> EngineAvalonia["Engine.cs (Avalonia)<br/>Orchestrates startup/shutdown"]
EngineAvalonia --> EngineShared["Engine.cs (Shared)<br/>Lifecycle hooks & contracts"]
EngineAvalonia --> Dispatcher["AvaloniaDispatcher.cs<br/>IDispatcher impl"]
EngineAvalonia --> UIInvoker["AvaloniaUIInvoker.cs<br/>IUIInvoker impl"]
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
## Core Components
- Engine (Avalonia): Orchestrates application startup, initializes subsystems, loads plugins, and manages shutdown.
- Engine (Shared): Defines lifecycle hooks and contracts for platform-specific implementations.
- IDispatcher: Abstraction for scheduling work on a specific thread or context.
- IUIInvoker: Abstraction for invoking UI updates safely from background threads.
- AvaloniaDispatcher: Concrete dispatcher backed by Avalonia’s threading model.
- AvaloniaUIInvoker: Concrete UI invoker that marshals calls onto the UI thread.
Key responsibilities:
- Startup sequence: create services, configure logging, load configuration, initialize networking, macros, agents, and UI components.
- Event-driven coordination: publish and subscribe to engine events to decouple subsystems.
- Plugin discovery and initialization: scan assemblies, instantiate extensions, and register them with the engine.
- Thread management: ensure background tasks run off the UI thread and UI updates are dispatched back to the UI thread.
- Graceful shutdown: stop network loops, cancel timers, flush logs, release resources, and close UI windows.
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Architecture Overview
The Engine acts as the central coordinator. It uses an event bus to communicate between components such as network handlers, macro system, agents, and UI. Subsystems register event handlers during initialization and react to engine events like Start, Stop, Connected, Disconnected, MacroExecuted, AgentStateChanged, etc.
```mermaid
sequenceDiagram
participant Main as "Program"
participant App as "App"
participant Eng as "Engine (Avalonia)"
participant Net as "Network Handler"
participant Mac as "Macro System"
participant Ag as "Agents"
participant UI as "UI Layer"
Main->>App : Initialize UI framework
App->>Eng : Create and start Engine
Eng->>Eng : Load configuration
Eng->>Eng : Discover and load plugins
Eng->>Net : Initialize network stack
Eng->>Mac : Initialize macro engine
Eng->>Ag : Initialize agent managers
Eng->>UI : Initialize UI components
Eng-->>Net : Event : Started
Eng-->>Mac : Event : Started
Eng-->>Ag : Event : Started
Eng-->>UI : Event : Started
Net-->>Eng : Event : Connected
Eng-->>UI : Dispatch UI update via IUIInvoker
Mac-->>Eng : Event : MacroExecuted
Eng-->>Ag : Publish event to agents
Ag-->>Eng : Event : StateChanged
Eng-->>UI : Update UI state
Eng->>Eng : Shutdown requested
Eng-->>Net : Event : Stopping
Eng-->>Mac : Event : Stopping
Eng-->>Ag : Event : Stopping
Eng-->>UI : Close windows and release resources
Eng-->>Main : Exit
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Detailed Component Analysis
### Engine Lifecycle Orchestration
The Engine lifecycle follows a clear sequence:
- Pre-start: parse arguments, set up logging, load profiles/configuration.
- Start: initialize subsystems (network, macros, agents), load plugins, start event loop.
- Running: handle events from subsystems, coordinate cross-thread UI updates, manage timers and queues.
- Shutdown: signal stopping to all subsystems, wait for completion, release resources, exit cleanly.
```mermaid
flowchart TD
Start(["Engine.Start"]) --> PreStart["Pre-start: config, logging, profile"]
PreStart --> InitSubsystems["Initialize subsystems<br/>Network, Macros, Agents"]
InitSubsystems --> LoadPlugins["Discover and load plugins"]
LoadPlugins --> StartEvents["Start event loop and listeners"]
StartEvents --> Running["Running: process events"]
Running --> ShutdownRequested{"Shutdown requested?"}
ShutdownRequested --> |No| Running
ShutdownRequested --> |Yes| SignalStop["Signal Stop to subsystems"]
SignalStop --> Cleanup["Cleanup resources and UI"]
Cleanup --> End(["Engine.Stop complete"])
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Event-Driven Communication Model
The Engine exposes events that subsystems can subscribe to. Typical events include:
- Application-level: Started, Stopping, Stopped
- Network-level: Connected, Disconnected, PacketReceived
- Macro-level: MacroExecuted, MacroError
- Agent-level: AgentStateChanged, AgentActionPerformed
- UI-level: UpdateRequested, WindowClosed
Subsystems publish events through the Engine’s event bus. For example, when the network handler connects, it raises a Connected event; the Engine publishes this to subscribers, including UI components that update status indicators.
```mermaid
classDiagram
class Engine {
+Event Started
+Event Stopping
+Event Stopped
+Event Connected
+Event Disconnected
+Event MacroExecuted
+Event AgentStateChanged
+Publish(event, data)
+Subscribe(event, handler)
}
class NetworkHandler {
+Connect()
+Disconnect()
+OnConnected()
+OnDisconnected()
}
class MacroSystem {
+Execute(macro)
+OnError(error)
}
class Agents {
+HandleStateChange(state)
}
class UIUpdater {
+UpdateStatus(status)
+RefreshViews()
}
Engine <.. NetworkHandler : "publishes Connected/Disconnected"
Engine <.. MacroSystem : "publishes MacroExecuted/MacroError"
Engine <.. Agents : "publishes AgentStateChanged"
Engine <.. UIUpdater : "publishes UI updates"
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Plugin Loading Mechanism
Plugin discovery and initialization follow these steps:
- Scan configured directories for assemblies.
- Identify types implementing known extension interfaces or attributes.
- Instantiate plugin instances and call their Initialize method.
- Register plugin-provided commands, filters, agents, or UI tabs with the Engine.
```mermaid
flowchart TD
Scan["Scan assembly directories"] --> Identify["Identify plugin types"]
Identify --> Instantiate["Instantiate plugin instances"]
Instantiate --> Initialize["Call Initialize(pluginContext)"]
Initialize --> Register["Register commands/filters/agents/UI"]
Register --> Ready["Plugins ready"]
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
### Thread Management Strategy
Cross-thread concerns are handled via:
- IDispatcher: schedules work on a target thread or context.
- IUIInvoker: marshals UI updates onto the UI thread.
- Background workers: network processing, macro execution, and agent logic run off the UI thread.
```mermaid
sequenceDiagram
participant BG as "Background Task"
participant Eng as "Engine"
participant Disp as "IDispatcher"
participant UIInv as "IUIInvoker"
participant UI as "UI Thread"
BG->>Eng : Request UI update
Eng->>UIInv : Invoke(updateCallback)
UIInv->>Disp : ScheduleOnUIThread(callback)
Disp-->>UI : Execute callback on UI thread
UI-->>UIInv : Completed
UIInv-->>Eng : Acknowledge
Eng-->>BG : Continue processing
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
### Custom Engine Extension Points
To integrate new features into the engine lifecycle:
- Implement a plugin type recognized by the loader.
- Provide an Initialize(context) method to register your feature.
- Subscribe to relevant Engine events to react to lifecycle changes.
- Use IUIInvoker for any UI updates from background threads.
- Ensure your feature cleans up resources in response to Stopping events.
Example integration steps:
- Add your assembly to the plugin directory.
- Define a class implementing the expected interface or attribute.
- In Initialize, register commands, filters, agents, or UI tabs.
- Subscribe to Engine events for Connected/Disconnected, MacroExecuted, AgentStateChanged.
- On Stopping, cancel timers, dispose resources, and detach event handlers.
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
## Dependency Analysis
The Engine depends on shared contracts and platform-specific implementations:
- Shared contracts: IDispatcher, IUIInvoker, Engine base behavior.
- Platform implementations: AvaloniaDispatcher, AvaloniaUIInvoker.
- Subsystems: Network, Macros, Agents, UI.
```mermaid
graph TB
EngineAvalonia["Engine.cs (Avalonia)"] --> EngineShared["Engine.cs (Shared)"]
EngineAvalonia --> IDisp["IDispatcher.cs"]
EngineAvalonia --> IUI["IUIInvoker.cs"]
EngineAvalonia --> AvalDisp["AvaloniaDispatcher.cs"]
EngineAvalonia --> AvalUI["AvaloniaUIInvoker.cs"]
EngineAvalonia --> Subsystems["Network, Macros, Agents, UI"]
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Performance Considerations
- Avoid heavy work on the UI thread; always use IUIInvoker for UI updates.
- Batch UI updates where possible to reduce redraw overhead.
- Use efficient event subscriptions; unsubscribe during shutdown to prevent leaks.
- Prefer asynchronous operations for network and file I/O.
- Limit plugin scanning frequency; cache discovered plugins when appropriate.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- UI not updating: ensure updates are invoked via IUIInvoker and scheduled on the UI thread using IDispatcher.
- Plugins not loading: verify plugin assemblies are in the correct directory and implement the expected interfaces/attributes.
- Events not firing: confirm subscriptions occur after Engine.Start and unsubscriptions occur before Engine.Stop.
- Resource leaks: check that background tasks are cancelled and resources disposed during Stopping.
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
## Conclusion
The Engine in ClassicAssist.Avalonia serves as the central orchestrator for application lifecycle, coordinating subsystem initialization, event-driven communication, plugin loading, and graceful shutdown. By adhering to the provided extension points and thread management strategies, developers can integrate new features seamlessly while maintaining responsiveness and stability.
[No sources needed since this section summarizes without analyzing specific files]
@@ -0,0 +1,382 @@
# MVVM Pattern Implementation
<cite>
**Referenced Files in This Document**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
</cite>
## 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. [Troubleshooting Guide](#troubleshooting-guide)
9. [Conclusion](#conclusion)
## Introduction
This document explains how the Model-View-ViewModel (MVVM) pattern is implemented in ClassicAssist.Avalonia. It focuses on separation of concerns between Views (AXAML), ViewModels (C# classes), and Models (business logic), with emphasis on:
- The BaseViewModel that provides common functionality such as property change notification and command binding
- Data binding mechanisms and event handling patterns
- Lifecycle management of ViewModels
- Concrete examples from MainWindow and other key views
- Testing strategies for ViewModels and best practices to maintain clean separation between presentation logic and business rules
## Project Structure
The Avalonia UI layer follows a clear folder structure aligned with MVVM:
- Views are defined in AXAML files under ClassicAssist.Avalonia/Views, with code-behind files (.axaml.cs) kept minimal
- ViewModels live in ClassicAssist.Shared/UI/ViewModels and implement presentation logic and data binding
- Models and shared services reside in ClassicAssist.Shared, including UI infrastructure like dispatchers and UI invokers
- App initialization wires up the root ViewModel and ensures UI updates occur on the correct thread
```mermaid
graph TB
subgraph "Avalonia UI Layer"
A_MainWindow["MainWindow.axaml<br/>Code-behind: MainWindow.axaml.cs"]
A_GeneralControl["GeneralControl.axaml<br/>Code-behind: GeneralControl.axaml.cs"]
A_DialogWindow["DialogWindow.axaml<br/>Code-behind: DialogWindow.axaml.cs"]
end
subgraph "Shared UI Infrastructure"
B_BaseViewModel["BaseViewModel.cs"]
B_IDispatcher["IDispatcher.cs"]
B_IUIInvoker["IUIInvoker.cs"]
B_AvaloniaDispatcher["AvaloniaDispatcher.cs"]
B_AvaloniaUIInvoker["AvaloniaUIInvoker.cs"]
end
subgraph "Shared Business Logic"
C_Models["Models and Managers<br/>(ClassicAssist.Shared/Data/*)"]
end
A_MainWindow --> B_BaseViewModel
A_GeneralControl --> B_BaseViewModel
A_DialogWindow --> B_BaseViewModel
B_BaseViewModel --> B_IDispatcher
B_BaseViewModel --> B_IUIInvoker
B_AvaloniaDispatcher --> B_IDispatcher
B_AvaloniaUIInvoker --> B_IUIInvoker
A_MainWindow --> C_Models
A_GeneralControl --> C_Models
A_DialogWindow --> C_Models
```
**Diagram sources**
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
## Core Components
- BaseViewModel: Provides common MVVM utilities such as property change notification and command support. All ViewModels inherit from this base to ensure consistent behavior and reduce boilerplate.
- MainWindowViewModel: Root ViewModel for the main window; orchestrates UI state and delegates business operations to models/managers.
- DialogWindowViewModel: Lightweight ViewModel used by modal dialogs to expose properties and commands bound from AXAML.
- GeneralControlViewModel: Example of a reusable control ViewModel demonstrating encapsulated presentation logic.
- Dispatcher and UI Invoker abstractions: Ensure UI updates occur on the UI thread regardless of background work.
Key responsibilities:
- Views (AXAML): Define layout, styling, and declarative bindings to ViewModel properties and commands. Code-behind should remain thin and avoid business logic.
- ViewModels: Expose bindable properties and commands, handle user interactions, coordinate with models, and update UI state safely via dispatcher/invoker.
- Models: Contain business rules, data access, and domain logic. They do not depend on UI frameworks.
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Architecture Overview
At runtime, the application initializes the UI framework, creates the root ViewModel, and sets it as the DataContext for the main view. ViewModels use the dispatcher to marshal UI updates onto the UI thread and invoke UI helpers through the UI invoker abstraction.
```mermaid
sequenceDiagram
participant App as "App.axaml.cs"
participant Program as "Program.cs"
participant MainWindow as "MainWindow.axaml"
participant VM as "MainWindowViewModel"
participant Dispatcher as "AvaloniaDispatcher"
participant UIInvoker as "AvaloniaUIInvoker"
Program->>App : Initialize UI framework
App->>MainWindow : Create main window
App->>VM : Instantiate root ViewModel
App->>MainWindow : Set DataContext = VM
MainWindow-->>VM : Bindings resolve properties/commands
VM->>Dispatcher : ExecuteOnUIThread(action)
Dispatcher-->>MainWindow : Invoke UI update
VM->>UIInvoker : Show dialog / message
UIInvoker-->>MainWindow : Present UI element
```
**Diagram sources**
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Detailed Component Analysis
### BaseViewModel
BaseViewModel centralizes MVVM essentials:
- Property change notification: Derived classes raise notifications when properties change so bindings update automatically.
- Command support: Common command infrastructure enables binding user actions to methods or ICommand implementations.
- Thread safety helpers: Integration with dispatcher/invoker to ensure UI updates happen on the UI thread.
Best practices:
- Always raise property change notifications after updating backing fields.
- Use commands for all user interactions exposed to AXAML.
- Avoid direct UI references; rely on dispatcher and UI invoker abstractions.
```mermaid
classDiagram
class BaseViewModel {
+RaisePropertyChanged(propertyName)
+ExecuteCommand(command)
+EnsureUiThread(action)
}
class MainWindowViewModel {
+Properties...
+Commands...
+Initialize()
}
class DialogWindowViewModel {
+Title
+Message
+OkCommand
+CancelCommand
}
class GeneralControlViewModel {
+State
+RefreshCommand
}
MainWindowViewModel --|> BaseViewModel
DialogWindowViewModel --|> BaseViewModel
GeneralControlViewModel --|> BaseViewModel
```
**Diagram sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
### MainWindow and MainWindowViewModel
The main window demonstrates typical MVVM usage:
- AXAML defines controls and binds their properties and commands to MainWindowViewModel members.
- Code-behind remains minimal, typically only wiring up initial DataContext if needed.
- MainWindowViewModel exposes properties for UI state and commands for user actions, coordinating with models/managers.
Data binding flow:
- User interaction triggers a command in MainWindowViewModel.
- ViewModel updates properties and raises notifications.
- AXAML bindings reflect changes automatically.
```mermaid
sequenceDiagram
participant View as "MainWindow.axaml"
participant VM as "MainWindowViewModel"
participant Dispatcher as "AvaloniaDispatcher"
View->>VM : Command invoked (e.g., "OpenSettings")
VM->>VM : Perform action / update state
VM->>Dispatcher : EnsureUiThread(updateUI)
Dispatcher-->>View : Update bound properties
View-->>User : Reflect new state
```
**Diagram sources**
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
**Section sources**
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
### DialogWindow and DialogWindowViewModel
Modal dialogs follow the same MVVM principles:
- DialogWindow.axaml binds to DialogWindowViewModel properties (title, message) and commands (OK, Cancel).
- DialogWindowViewModel encapsulates dialog-specific state and actions without referencing UI elements directly.
```mermaid
flowchart TD
Start(["Show Dialog"]) --> Bind["Bind Title/Message/Commands"]
Bind --> UserAction{"User clicks OK or Cancel?"}
UserAction --> |OK| Confirm["Confirm action in ViewModel"]
UserAction --> |Cancel| Close["Close dialog"]
Confirm --> UpdateUI["Update UI via dispatcher"]
UpdateUI --> End(["Dialog Closed"])
Close --> End
```
**Diagram sources**
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
**Section sources**
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
### GeneralControl and GeneralControlViewModel
Reusable controls demonstrate encapsulation:
- GeneralControl.axaml binds to GeneralControlViewModel properties and commands.
- GeneralControlViewModel manages its own state and exposes a refresh command, keeping the control self-contained and testable.
```mermaid
classDiagram
class GeneralControl {
<<AXAML>>
+Bindings to ViewModel
}
class GeneralControlViewModel {
+State
+RefreshCommand
+Initialize()
}
GeneralControl --> GeneralControlViewModel : "DataContext"
```
**Diagram sources**
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
**Section sources**
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
### Dispatcher and UI Invoker Abstractions
To keep ViewModels UI-framework agnostic:
- IDispatcher and IUIInvoker define contracts for executing code on the UI thread and invoking UI operations.
- AvaloniaDispatcher and AvaloniaUIInvoker provide concrete implementations for Avalonia.
```mermaid
classDiagram
class IDispatcher {
+ExecuteOnUIThread(action)
}
class IUIInvoker {
+ShowDialog(dialogViewModel)
+ShowMessage(message)
}
class AvaloniaDispatcher {
+ExecuteOnUIThread(action)
}
class AvaloniaUIInvoker {
+ShowDialog(dialogViewModel)
+ShowMessage(message)
}
IDispatcher <|.. AvaloniaDispatcher
IUIInvoker <|.. AvaloniaUIInvoker
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Dependency Analysis
ViewModels depend on:
- BaseViewModel for common functionality
- Dispatcher and UI invoker abstractions for cross-thread UI updates
- Models/managers for business logic (not shown here but present in Shared/Data)
```mermaid
graph LR
VM_Main["MainWindowViewModel"] --> Base["BaseViewModel"]
VM_Dialog["DialogWindowViewModel"] --> Base
VM_General["GeneralControlViewModel"] --> Base
Base --> Disp["IDispatcher"]
Base --> Inv["IUIInvoker"]
Disp --> DispImpl["AvaloniaDispatcher"]
Inv --> InvImpl["AvaloniaUIInvoker"]
```
**Diagram sources**
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Performance Considerations
- Minimize heavy work on the UI thread; offload to background tasks and marshal results back using the dispatcher.
- Use efficient collections and avoid unnecessary property updates; batch updates where possible.
- Keep AXAML bindings simple and avoid complex converters in hot paths.
- Reuse ViewModels and controls when appropriate to reduce allocation overhead.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- UI not updating after property changes: Ensure property change notifications are raised correctly in BaseViewModel-derived classes.
- Cross-thread exceptions: Always use the dispatcher to execute UI updates from background threads.
- Commands not firing: Verify command bindings in AXAML and that commands are properly exposed and enabled.
- Dialogs not showing: Use the UI invoker abstraction to present dialogs instead of direct UI calls.
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Conclusion
ClassicAssist.Avalonia implements MVVM cleanly by separating Views (AXAML), ViewModels (C#), and Models (business logic). BaseViewModel standardizes property change notification and command support, while dispatcher and UI invoker abstractions ensure thread-safe UI updates. MainWindow, DialogWindow, and GeneralControl illustrate proper MVVM usage, enabling testable and maintainable presentation logic. Following these patterns helps keep the UI responsive and the codebase organized.
[No sources needed since this section summarizes without analyzing specific files]
@@ -0,0 +1,530 @@
# Networking Fundamentals
<cite>
**Referenced Files in This Document**
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [ActionPacketQueueItem.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueueItem.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
- [Packet.cs](file://ClassicAssist.Shared/UO/Objects/Packet.cs)
</cite>
## 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. [Troubleshooting Guide](#troubleshooting-guide)
9. [Conclusion](#conclusion)
10. [Appendices](#appendices)
## Introduction
This document explains the networking fundamentals of ClassicAssist.Avalonia with a focus on the Ultima Online packet protocol implementation. It covers how packets are parsed, serialized, and deserialized; how incoming and outgoing packets are routed through a handler system; how game entities (objects, mobiles, items) are created, updated, and destroyed based on network events; compression algorithms used for efficiency; error handling strategies; examples of custom packet handlers; extension points for new protocol features; performance considerations for high-frequency processing; and memory management strategies.
## Project Structure
The networking layer is primarily implemented under ClassicAssist.Shared/UO/Network and ClassicAssist.Shared/UO/Data, with supporting object models under ClassicAssist.Shared/UO/Objects. Key areas include:
- Packet I/O primitives: PacketReader and PacketWriter
- Packet base types and concrete packet definitions
- Incoming and outgoing packet routing via handler registries
- Filtering and queuing mechanisms
- Compression utilities
- Entity lifecycle models and collections
```mermaid
graph TB
subgraph "Networking Layer"
PR["PacketReader"]
PW["PacketWriter"]
PH["PacketHandler"]
IPH["IncomingPacketHandlers"]
OPH["OutgoingPacketHandlers"]
IF["IncomingPacketFilters"]
OF["OutgoingPacketFilters"]
APQ["ActionPacketQueue"]
COMP["Compression"]
end
subgraph "Packets"
BP["BasePacket"]
MI["MobileIncoming"]
MU["MobileUpdate"]
RO["RemoveObject"]
end
subgraph "Objects"
ENT["Entity"]
ECOL["EntityCollection"]
MOB["Mobile"]
PMOB["PlayerMobile"]
ITM["Item"]
PKT["Packet"]
end
PR --> PH
PH --> IPH
PH --> IF
PH --> APQ
PW --> OPH
PW --> OF
PH --> COMP
BP --> MI
BP --> MU
BP --> RO
ENT --> ECOL
MOB --> ENT
PMOB --> MOB
ITM --> ENT
PKT --> BP
```
**Diagram sources**
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
- [Packet.cs](file://ClassicAssist.Shared/UO/Objects/Packet.cs)
**Section sources**
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
- [Packet.cs](file://ClassicAssist.Shared/UO/Objects/Packet.cs)
## Core Components
- Packet I/O primitives:
- PacketReader provides methods to read UO-specific data types from streams or buffers.
- PacketWriter provides methods to serialize UO-specific data types into streams or buffers.
- Packet base model:
- BasePacket defines common fields and serialization/deserialization hooks used by all concrete packets.
- Concrete packets:
- Examples include MobileIncoming, MobileUpdate, RemoveObject, which encapsulate specific UO message formats.
- Handler registries:
- IncomingPacketHandlers and OutgoingPacketHandlers maintain mappings between packet IDs and handler methods.
- Packet routing:
- PacketHandler orchestrates reading/writing, dispatching to filters and handlers, and managing queues.
- Filters:
- IncomingPacketFilters and OutgoingPacketFilters allow selective inspection, modification, or blocking of packets.
- Queues:
- ActionPacketQueue batches and orders actions derived from packets to ensure deterministic updates.
- Compression:
- Compression utilities implement UO’s packet compression scheme to reduce bandwidth usage.
- Entities:
- Entity, Mobile, PlayerMobile, Item, and their collections represent game objects whose lifecycle is driven by network events.
**Section sources**
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
## Architecture Overview
The networking architecture follows a pipeline pattern:
- Incoming path:
- Raw bytes are decompressed if needed, then read using PacketReader.
- PacketHandler identifies the packet type and routes it through IncomingPacketFilters.
- The appropriate IncomingPacketHandlers method is invoked to update state or enqueue actions.
- Outgoing path:
- Application code constructs packets using PacketWriter.
- OutgoingPacketFilters inspect or modify packets before sending.
- PacketHandler serializes and transmits packets, optionally compressing them.
```mermaid
sequenceDiagram
participant Net as "Network Stream"
participant Comp as "Compression"
participant Reader as "PacketReader"
participant PH as "PacketHandler"
participant IF as "IncomingPacketFilters"
participant IH as "IncomingPacketHandlers"
participant Queue as "ActionPacketQueue"
participant Coll as "EntityCollection"
Net->>Comp : "Receive compressed bytes"
Comp-->>Net : "Decompressed payload"
Net->>Reader : "Read packet header"
Reader->>PH : "Dispatch by packet ID"
PH->>IF : "Apply incoming filters"
IF-->>PH : "Filtered packet"
PH->>IH : "Invoke registered handler"
IH->>Coll : "Create/Update/Delete entities"
IH->>Queue : "Enqueue follow-up actions"
Queue-->>Coll : "Process queued actions"
```
**Diagram sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
## Detailed Component Analysis
### Packet Parsing, Serialization, and Deserialization
- PacketReader and PacketWriter provide typed accessors for UO data formats (e.g., integers, strings, coordinates). They abstract low-level byte operations and ensure consistent parsing across the application.
- BasePacket defines common fields and virtual methods for serialization/deserialization. Concrete packets override these methods to encode/decode their specific payloads.
- Example flows:
- Incoming: Decompress -> Read header -> Instantiate concrete packet -> Deserialize fields -> Route to handler.
- Outgoing: Construct concrete packet -> Serialize fields -> Apply outgoing filters -> Compress -> Send.
```mermaid
flowchart TD
Start(["Start"]) --> ReadHeader["Read packet header"]
ReadHeader --> Identify{"Identify packet type"}
Identify --> |Known| CreatePacket["Instantiate concrete packet"]
Identify --> |Unknown| LogWarn["Log warning and skip"]
CreatePacket --> Deserialize["Deserialize fields"]
Deserialize --> Route["Route to handler registry"]
Route --> End(["End"])
LogWarn --> End
```
**Diagram sources**
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
**Section sources**
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
### Packet Handler System
- IncomingPacketHandlers and OutgoingPacketHandlers maintain registration maps that associate packet IDs with handler methods.
- PacketHandler centralizes dispatch logic, invoking filters and handlers in sequence.
- Registration typically occurs during initialization, allowing modular addition of new packet support.
```mermaid
classDiagram
class PacketHandler {
+registerIncoming(id, handler)
+registerOutgoing(id, handler)
+dispatchIncoming(packet)
+dispatchOutgoing(packet)
}
class IncomingPacketHandlers {
+handlers : Map<int, Func>
+invoke(id, packet)
}
class OutgoingPacketHandlers {
+handlers : Map<int, Func>
+invoke(id, packet)
}
class IncomingPacketFilters {
+apply(packet) bool
}
class OutgoingPacketFilters {
+apply(packet) bool
}
PacketHandler --> IncomingPacketHandlers : "uses"
PacketHandler --> OutgoingPacketHandlers : "uses"
PacketHandler --> IncomingPacketFilters : "applies"
PacketHandler --> OutgoingPacketFilters : "applies"
```
**Diagram sources**
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
**Section sources**
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
### Entity Lifecycle Management
- Entities are represented by Entity and its subclasses (Mobile, PlayerMobile, Item), managed by EntityCollection.
- Network events drive lifecycle transitions:
- Creation: Packets like MobileIncoming add new entities to collections.
- Update: Packets like MobileUpdate modify entity properties (position, appearance, status).
- Destruction: Packets like RemoveObject remove entities from collections and release resources.
```mermaid
sequenceDiagram
participant PH as "PacketHandler"
participant IH as "IncomingPacketHandlers"
participant Coll as "EntityCollection"
participant Ent as "Entity"
PH->>IH : "Handle MobileIncoming"
IH->>Coll : "Add new Mobile/Item"
Coll->>Ent : "Initialize entity state"
PH->>IH : "Handle MobileUpdate"
IH->>Ent : "Update properties"
PH->>IH : "Handle RemoveObject"
IH->>Coll : "Remove entity"
Coll->>Ent : "Dispose resources"
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
**Section sources**
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
### Compression Algorithms
- Compression utilities implement UO’s packet compression scheme to minimize bandwidth usage.
- Incoming packets may be decompressed before parsing; outgoing packets may be compressed before transmission.
- Proper handling ensures compatibility with server expectations and avoids corruption.
```mermaid
flowchart TD
InStart(["Incoming Bytes"]) --> CheckFlag{"Compressed?"}
CheckFlag --> |Yes| Decompress["Decompress payload"]
CheckFlag --> |No| Parse["Parse directly"]
Decompress --> Parse
Parse --> End(["Parsed Packet"])
OutStart(["Serialized Packet"]) --> Compress["Compress payload"]
Compress --> OutEnd(["Send Compressed Bytes"])
```
**Diagram sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
**Section sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
### Error Handling Strategies
- Unknown packet IDs should be logged and skipped to prevent crashes.
- Malformed packets should trigger validation failures and safe recovery paths.
- Connection issues should be handled by retry logic, reconnection attempts, and graceful degradation.
- Filters can block suspicious or malformed packets early in the pipeline.
[No sources needed since this section provides general guidance]
### Custom Packet Handlers and Extensibility
- To add support for a new packet:
- Define a concrete packet class extending BasePacket with serialization/deserialization logic.
- Register an incoming handler in IncomingPacketHandlers mapping the packet ID to your method.
- Optionally register an outgoing handler in OutgoingPacketHandlers for client-initiated messages.
- Use filters in IncomingPacketFilters/OutgoingPacketFilters for inspection or modification.
- Update entity collections or enqueue actions via ActionPacketQueue as needed.
```mermaid
sequenceDiagram
participant Dev as "Developer Code"
participant Reg as "IncomingPacketHandlers"
participant PH as "PacketHandler"
participant Coll as "EntityCollection"
Dev->>Reg : "Register handler for new packet ID"
PH->>Reg : "Lookup handler by ID"
Reg-->>PH : "Handler method"
PH->>Dev : "Invoke handler"
Dev->>Coll : "Update/create entities"
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
### Performance Considerations and Memory Management
- High-frequency packet processing:
- Minimize allocations in hot paths; reuse buffers where possible.
- Keep handler logic lightweight; defer heavy work to ActionPacketQueue.
- Avoid excessive logging in tight loops; use sampling or thresholds.
- Memory management:
- Ensure entities dispose resources when removed to prevent leaks.
- Use efficient collections in EntityCollection for fast lookups and removals.
- Be mindful of string interning and large payload sizes.
- Threading:
- Separate network I/O threads from UI/update threads; marshal updates safely.
- Use thread-safe queues and synchronization primitives.
[No sources needed since this section provides general guidance]
## Dependency Analysis
The following diagram highlights key dependencies among networking components and object models.
```mermaid
graph TB
PH["PacketHandler"] --> IPH["IncomingPacketHandlers"]
PH --> OPH["OutgoingPacketHandlers"]
PH --> IF["IncomingPacketFilters"]
PH --> OF["OutgoingPacketFilters"]
PH --> APQ["ActionPacketQueue"]
PH --> PR["PacketReader"]
PH --> PW["PacketWriter"]
PH --> COMP["Compression"]
IPH --> MI["MobileIncoming"]
IPH --> MU["MobileUpdate"]
IPH --> RO["RemoveObject"]
MI --> ENT["Entity"]
MU --> ENT
RO --> ENT
ENT --> ECOL["EntityCollection"]
ENT --> MOB["Mobile"]
MOB --> PMOB["PlayerMobile"]
ENT --> ITM["Item"]
```
**Diagram sources**
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
**Section sources**
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [RemoveObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/RemoveObject.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
## Performance Considerations
- Batch updates:
- Use ActionPacketQueue to coalesce multiple entity updates into fewer UI refreshes.
- Efficient parsing:
- Prefer direct reads over reflection-based deserialization.
- Reduce GC pressure:
- Reuse temporary buffers and avoid unnecessary string allocations.
- Selective filtering:
- Drop irrelevant packets early to save CPU cycles.
- Profiling:
- Monitor hot paths and identify bottlenecks in packet handlers.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
- Symptoms:
- Missing entities or stale state: Verify incoming handlers for creation/update packets.
- Crashes on unknown packets: Ensure unknown IDs are logged and skipped gracefully.
- High CPU usage: Check for heavy operations in handlers; move to queue or background tasks.
- Memory growth: Inspect entity disposal and collection cleanup.
- Steps:
- Enable detailed logging for packet IDs and sizes.
- Validate packet lengths and field ranges before processing.
- Test with filtered traffic to isolate problematic packets.
- Review compression/decompression boundaries for errors.
[No sources needed since this section provides general guidance]
## Conclusion
ClassicAssist.Avalonia implements a robust networking layer tailored to the Ultima Online protocol. By leveraging typed readers/writers, a centralized handler system, filters, queues, and compression, the application efficiently processes high-frequency network events while maintaining clear separation of concerns. Entity lifecycle management is driven by well-defined packet handlers, ensuring consistent state synchronization. Extensibility is straightforward through handler registration and filter application, and performance can be optimized by careful memory management and batching strategies.
## Appendices
- Best practices:
- Always validate packet headers and lengths.
- Keep handlers idempotent and side-effect minimal.
- Use filters for diagnostics and security checks.
- Dispose entities promptly upon removal.
- Extension checklist:
- Define packet class with serialization/deserialization.
- Register incoming/outgoing handlers.
- Add filters if necessary.
- Update entity collections or enqueue actions.
- Test with real traffic and edge cases.
[No sources needed since this section provides general guidance]
@@ -0,0 +1,580 @@
# Plugin Architecture
<cite>
**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)
- [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)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.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)
- [ClilocFilter.cs](file://ClassicAssist.Shared/Data/Filters/ClilocFilter.cs)
- [RepeatedMessagesFilter.cs](file://ClassicAssist.Shared/Data/Filters/RepeatedMessagesFilter.cs)
- [BardsMusicFilter.cs](file://ClassicAssist.Shared/Data/Filters/BardsMusicFilter.cs)
- [LightLevelFilter.cs](file://ClassicAssist.Shared/Data/Filters/LightLevelFilter.cs)
- [SeasonFilter.cs](file://ClassicAssist.Shared/Data/Filters/SeasonFilter.cs)
- [WeatherFilter.cs](file://ClassicAssist.Shared/Data/Filters/WeatherFilter.cs)
- [IConfigurableFilter.cs](file://ClassicAssist.Shared/Data/Filters/IConfigurableFilter.cs)
- [FilterOptionsAttribute.cs](file://ClassicAssist.Shared/Data/Filters/FilterOptionsAttribute.cs)
- [DynamicFilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/DynamicFilterEntry.cs)
- [HotkeyEntry.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyEntry.cs)
- [ShortcutKeys.cs](file://ClassicAssist.Shared/Data/Hotkeys/ShortcutKeys.cs)
- [HotkeyChangedEventArgs.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyChangedEventArgs.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [MacroEntry.cs](file://ClassicAssist.Shared/Data/Macros/MacroEntry.cs)
- [ParameterType.cs](file://ClassicAssist.Shared/Data/Macros/ParameterType.cs)
- [SystemMessageTextWriter.cs](file://ClassicAssist.Shared/Data/Macros/SystemMessageTextWriter.cs)
- [UseOnceList.cs](file://ClassicAssist.Shared/Data/Macros/UseOnceList.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
</cite>
## 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. [Troubleshooting Guide](#troubleshooting-guide)
9. [Conclusion](#conclusion)
10. [Appendices](#appendices)
## Introduction
This document explains the plugin architecture and extensibility model in ClassicAssist.Avalonia. It focuses on how developers can extend functionality through:
- Plugins discovered at runtime via attribute-based registration
- Macro commands registered with attributes and invoked by a macro engine
- Hotkey bindings that trigger commands or macros
- A filter system for incoming and outgoing packets and UI messages
It also covers lifecycle management, dependency injection patterns used across the system, security considerations when loading external assemblies, and practical guidelines for creating and distributing plugins.
## Project Structure
The plugin-related features are implemented primarily in two layers:
- Shared core (ClassicAssist.Shared): defines interfaces, attributes, managers, and built-in implementations for hotkeys, macros, filters, and packet filtering.
- Avalonia host (ClassicAssist.Avalonia): bootstraps the application, initializes engines, and wires up platform-specific dispatching and UI invokers.
```mermaid
graph TB
subgraph "Host"
Program["Program.cs"]
App["App.axaml.cs"]
EngineAva["Engine.cs (Avalonia)"]
end
subgraph "Shared Core"
HotkeyMgr["HotkeyManager.cs"]
MacroMgr["MacroManager.cs"]
FiltersCore["Filters.cs"]
InPktF["IncomingPacketFilters.cs"]
OutPktF["OutgoingPacketFilters.cs"]
CmdMgr["CommandsManager.cs"]
end
Program --> App
App --> EngineAva
EngineAva --> HotkeyMgr
EngineAva --> MacroMgr
EngineAva --> FiltersCore
FiltersCore --> InPktF
FiltersCore --> OutPktF
EngineAva --> CmdMgr
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
## Core Components
- Attribute-based discovery and registration:
- Hotkey command attributes to register commands and bind them to keys.
- Macro command attributes to expose callable functions to the macro language.
- Filter attributes to configure UI options for filters.
- Managers and engines:
- Hotkey manager for binding and dispatching key combinations.
- Macro manager and invoker for parsing and executing macro scripts.
- Filter system for message and packet filtering.
- Platform abstractions:
- Dispatcher and UI invoker for cross-platform UI thread marshaling.
Key responsibilities:
- HotkeyManager: registers commands, binds shortcuts, raises events when keys are pressed.
- MacroManager/MacroInvoker: discovers macro commands, parses parameters, executes commands safely.
- Filters: centralizes filter registration and execution for both UI messages and network packets.
- CommandsManager: manages top-level commands available to users and macros.
**Section sources**
- [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)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Architecture Overview
The extensibility model is centered around attribute-driven discovery and manager orchestration. At startup, the host initializes engines and scans loaded assemblies for types decorated with specific attributes. These types are then registered into their respective managers. Runtime invocation flows from user actions (hotkeys, macros, UI) through managers to concrete implementations.
```mermaid
sequenceDiagram
participant Host as "Host (Engine.cs)"
participant Scanner as "Reflection Scanner"
participant HKM as "HotkeyManager"
participant MM as "MacroManager"
participant FI as "Filters"
participant Inv as "MacroInvoker"
Host->>Scanner : "Scan assemblies for attributes"
Scanner-->>HKM : "Register HotkeyCommandAttribute types"
Scanner-->>MM : "Register Macro command types"
Scanner-->>FI : "Register FilterEntry types"
Host->>HKM : "Bind shortcuts"
Host->>FI : "Enable filters"
Note over Host,FI : "Runtime ready"
User->>HKM : "Press shortcut"
HKM-->>Inv : "Invoke associated macro/command"
Inv->>MM : "Resolve and execute macro command"
MM-->>Inv : "Result"
Inv-->>User : "Effect applied"
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
## Detailed Component Analysis
### Attribute-Based Registration System
The system uses attributes to mark classes and methods for automatic discovery and registration:
- Hotkey commands: types implementing a base class or interface and decorated with an attribute that specifies metadata such as display name and default shortcut.
- Macro commands: methods or classes annotated to be discoverable by the macro engine.
- Filters: classes implementing a filter contract and optionally decorated with configuration attributes.
Registration typically occurs during engine initialization by scanning assemblies for these attributes and calling manager APIs to add entries.
```mermaid
classDiagram
class HotkeyCommandAttribute {
+string Name
+string Shortcut
}
class HotkeyCommand {
+Execute()
}
class HotkeyManager {
+Register(command)
+Bind(shortcut, command)
+OnKeyPressed(event)
}
class MacroManager {
+DiscoverCommands()
+Register(command)
}
class MacroInvoker {
+Invoke(name, args)
}
class FilterEntry {
+Apply(message) bool
}
class Filters {
+Register(filter)
+Process(message)
}
HotkeyManager --> HotkeyCommand : "registers"
HotkeyManager --> HotkeyCommandAttribute : "reads metadata"
MacroManager --> MacroInvoker : "invokes"
Filters --> FilterEntry : "applies"
```
**Diagram sources**
- [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)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
**Section sources**
- [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)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
### Command Registration Process for Macro Commands and Hotkey Bindings
- Macro command registration:
- The macro manager scans for command definitions (methods or classes) marked with appropriate attributes.
- Each command is parsed for parameter types and metadata, then stored in a registry accessible to the macro invoker.
- Hotkey binding:
- The hotkey manager reads attributes to determine default shortcuts and registers handlers.
- When a key combination is detected, the manager invokes the corresponding action, which may call into the macro invoker to run a macro command.
```mermaid
flowchart TD
Start(["Startup"]) --> Scan["Scan assemblies for attributes"]
Scan --> RegisterHK["Register Hotkey commands"]
Scan --> RegisterMC["Register Macro commands"]
RegisterHK --> BindShortcuts["Bind default shortcuts"]
RegisterMC --> Ready["Engines ready"]
BindShortcuts --> Ready
Ready --> Press["User presses shortcut"]
Press --> Dispatch["HotkeyManager dispatches"]
Dispatch --> InvokeMacro["MacroInvoker executes macro command"]
InvokeMacro --> End(["Done"])
```
**Diagram sources**
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [HotkeyCommandAttribute.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
**Section sources**
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [HotkeyCommandAttribute.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
### Filter System Architecture
The filter system supports both UI message filtering and network packet filtering:
- UI message filters implement a common entry type and are managed centrally.
- Packet filters integrate with incoming and outgoing filter pipelines.
- Some filters provide configuration UI via attributes.
```mermaid
classDiagram
class FilterEntry {
+bool Apply(object message)
}
class DynamicFilterEntry {
+object Options
}
class IConfigurableFilter {
+ShowConfigureDialog()
}
class FilterOptionsAttribute {
+string Title
+string Description
}
class ClilocFilter
class RepeatedMessagesFilter
class BardsMusicFilter
class LightLevelFilter
class SeasonFilter
class WeatherFilter
class IncomingPacketFilters
class OutgoingPacketFilters
class PacketFilter
class PacketFilterInfo
FilterEntry <|-- DynamicFilterEntry
IConfigurableFilter <|.. ClilocFilter
IConfigurableFilter <|.. RepeatedMessagesFilter
FilterOptionsAttribute ..> ClilocFilter
FilterOptionsAttribute ..> RepeatedMessagesFilter
IncomingPacketFilters --> PacketFilter : "uses"
OutgoingPacketFilters --> PacketFilter : "uses"
PacketFilter --> PacketFilterInfo : "configures"
```
**Diagram sources**
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [DynamicFilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/DynamicFilterEntry.cs)
- [IConfigurableFilter.cs](file://ClassicAssist.Shared/Data/Filters/IConfigurableFilter.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)
- [BardsMusicFilter.cs](file://ClassicAssist.Shared/Data/Filters/BardsMusicFilter.cs)
- [LightLevelFilter.cs](file://ClassicAssist.Shared/Data/Filters/LightLevelFilter.cs)
- [SeasonFilter.cs](file://ClassicAssist.Shared/Data/Filters/SeasonFilter.cs)
- [WeatherFilter.cs](file://ClassicAssist.Shared/Data/Filters/WeatherFilter.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)
**Section sources**
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [DynamicFilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/DynamicFilterEntry.cs)
- [IConfigurableFilter.cs](file://ClassicAssist.Shared/Data/Filters/IConfigurableFilter.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)
- [BardsMusicFilter.cs](file://ClassicAssist.Shared/Data/Filters/BardsMusicFilter.cs)
- [LightLevelFilter.cs](file://ClassicAssist.Shared/Data/Filters/LightLevelFilter.cs)
- [SeasonFilter.cs](file://ClassicAssist.Shared/Data/Filters/SeasonFilter.cs)
- [WeatherFilter.cs](file://ClassicAssist.Shared/Data/Filters/WeatherFilter.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)
### Practical Examples
#### Creating a Custom Macro Command
Steps:
- Define a method or class representing the command.
- Annotate it with the appropriate macro command attribute so the macro manager can discover it.
- Implement parameter handling using the defined parameter types.
- Ensure thread safety if interacting with game state; use the dispatcher to marshal UI updates.
References:
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [ParameterType.cs](file://ClassicAssist.Shared/Data/Macros/ParameterType.cs)
- [SystemMessageTextWriter.cs](file://ClassicAssist.Shared/Data/Macros/SystemMessageTextWriter.cs)
- [UseOnceList.cs](file://ClassicAssist.Shared/Data/Macros/UseOnceList.cs)
**Section sources**
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [ParameterType.cs](file://ClassicAssist.Shared/Data/Macros/ParameterType.cs)
- [SystemMessageTextWriter.cs](file://ClassicAssist.Shared/Data/Macros/SystemMessageTextWriter.cs)
- [UseOnceList.cs](file://ClassicAssist.Shared/Data/Macros/UseOnceList.cs)
#### Implementing a New Filter
Steps:
- Create a class implementing the filter entry contract.
- Optionally implement the configurable filter interface and decorate with filter options attributes to enable configuration UI.
- Register the filter during engine initialization or rely on attribute scanning.
- Implement the filtering logic in the apply method.
References:
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [IConfigurableFilter.cs](file://ClassicAssist.Shared/Data/Filters/IConfigurableFilter.cs)
- [FilterOptionsAttribute.cs](file://ClassicAssist.Shared/Data/Filters/FilterOptionsAttribute.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
Example built-ins for reference:
- [ClilocFilter.cs](file://ClassicAssist.Shared/Data/Filters/ClilocFilter.cs)
- [RepeatedMessagesFilter.cs](file://ClassicAssist.Shared/Data/Filters/RepeatedMessagesFilter.cs)
- [BardsMusicFilter.cs](file://ClassicAssist.Shared/Data/Filters/BardsMusicFilter.cs)
- [LightLevelFilter.cs](file://ClassicAssist.Shared/Data/Filters/LightLevelFilter.cs)
- [SeasonFilter.cs](file://ClassicAssist.Shared/Data/Filters/SeasonFilter.cs)
- [WeatherFilter.cs](file://ClassicAssist.Shared/Data/Filters/WeatherFilter.cs)
**Section sources**
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [IConfigurableFilter.cs](file://ClassicAssist.Shared/Data/Filters/IConfigurableFilter.cs)
- [FilterOptionsAttribute.cs](file://ClassicAssist.Shared/Data/Filters/FilterOptionsAttribute.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
- [ClilocFilter.cs](file://ClassicAssist.Shared/Data/Filters/ClilocFilter.cs)
- [RepeatedMessagesFilter.cs](file://ClassicAssist.Shared/Data/Filters/RepeatedMessagesFilter.cs)
- [BardsMusicFilter.cs](file://ClassicAssist.Shared/Data/Filters/BardsMusicFilter.cs)
- [LightLevelFilter.cs](file://ClassicAssist.Shared/Data/Filters/LightLevelFilter.cs)
- [SeasonFilter.cs](file://ClassicAssist.Shared/Data/Filters/SeasonFilter.cs)
- [WeatherFilter.cs](file://ClassicAssist.Shared/Data/Filters/WeatherFilter.cs)
#### Extending the Hotkey System
Steps:
- Create a new hotkey command class and annotate it with the hotkey command attribute to specify metadata and default shortcut.
- Ensure the command is discoverable by the reflection scanner during engine startup.
- Bind additional shortcuts programmatically if needed.
- Use the dispatcher to update UI elements safely.
References:
- [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)
- [ShortcutKeys.cs](file://ClassicAssist.Shared/Data/Hotkeys/ShortcutKeys.cs)
- [HotkeyChangedEventArgs.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyChangedEventArgs.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
**Section sources**
- [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)
- [ShortcutKeys.cs](file://ClassicAssist.Shared/Data/Hotkeys/ShortcutKeys.cs)
- [HotkeyChangedEventArgs.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyChangedEventArgs.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
### Plugin Lifecycle Management
Lifecycle phases:
- Discovery: scan assemblies for attribute-decorated types.
- Registration: add discovered components to managers (hotkeys, macros, filters).
- Initialization: perform any setup required by plugins.
- Runtime: respond to user actions (hotkeys, macros) and process messages/packets through filters.
- Shutdown: release resources and clean up registrations.
Implementation anchors:
- Host initialization and engine wiring:
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
### Dependency Injection Patterns
While there is no explicit DI container, the codebase uses constructor and property injection via managers and services:
- Managers hold references to shared services (e.g., dispatcher, UI invoker).
- Filters and commands receive dependencies through constructors or properties.
- The host wires up platform-specific implementations (dispatcher and UI invoker) before initializing managers.
References:
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
**Section sources**
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
### Security Considerations for Loaded Plugins
- Isolation: load plugin assemblies in separate contexts where possible to limit impact.
- Permissions: restrict access to sensitive APIs and file system operations.
- Validation: verify signatures and allowlists for trusted plugins.
- Sandboxing: avoid granting full trust to third-party code; prefer least privilege.
- Error containment: catch exceptions in plugin code paths to prevent crashes.
- Resource limits: throttle CPU and memory usage for plugin operations.
[No sources needed since this section provides general guidance]
## Dependency Analysis
High-level dependencies among plugin subsystems:
```mermaid
graph LR
HKAttr["HotkeyCommandAttribute.cs"] --> HKCmd["HotkeyCommand.cs"]
HKCmd --> HKM["HotkeyManager.cs"]
HKM --> HKEntry["HotkeyEntry.cs"]
HKM --> HKChanged["HotkeyChangedEventArgs.cs"]
HKM --> HKShortcut["ShortcutKeys.cs"]
MCAttr["MacroManager.cs"] --> MCI["MacroInvoker.cs"]
MCI --> Param["ParameterType.cs"]
MCI --> SysMsg["SystemMessageTextWriter.cs"]
MCI --> UseOnce["UseOnceList.cs"]
FCore["Filters.cs"] --> FEntry["FilterEntry.cs"]
FCore --> IFilt["IConfigurableFilter.cs"]
FCore --> FOpt["FilterOptionsAttribute.cs"]
FCore --> InPkt["IncomingPacketFilters.cs"]
FCore --> OutPkt["OutgoingPacketFilters.cs"]
InPkt --> PktF["PacketFilter.cs"]
OutPkt --> PktF
PktF --> PktInfo["PacketFilterInfo.cs"]
```
**Diagram sources**
- [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)
- [HotkeyChangedEventArgs.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyChangedEventArgs.cs)
- [ShortcutKeys.cs](file://ClassicAssist.Shared/Data/Hotkeys/ShortcutKeys.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [ParameterType.cs](file://ClassicAssist.Shared/Data/Macros/ParameterType.cs)
- [SystemMessageTextWriter.cs](file://ClassicAssist.Shared/Data/Macros/SystemMessageTextWriter.cs)
- [UseOnceList.cs](file://ClassicAssist.Shared/Data/Macros/UseOnceList.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
- [FilterEntry.cs](file://ClassicAssist.Shared/Data/Filters/FilterEntry.cs)
- [IConfigurableFilter.cs](file://ClassicAssist.Shared/Data/Filters/IConfigurableFilter.cs)
- [FilterOptionsAttribute.cs](file://ClassicAssist.Shared/Data/Filters/FilterOptionsAttribute.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)
**Section sources**
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
## Performance Considerations
- Minimize reflection overhead by caching discovered types and metadata.
- Avoid heavy work on the UI thread; use the dispatcher to offload tasks.
- Batch filter processing and short-circuit early when possible.
- Limit allocations in hot paths (packet filters, macro execution).
- Use efficient data structures for large collections (e.g., entity lists).
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- Hotkeys not firing:
- Verify attribute decoration and default shortcut values.
- Check for conflicts between multiple bindings.
- Ensure the hotkey manager is initialized and event listeners are active.
- Macro commands not found:
- Confirm the command is discoverable and properly attributed.
- Validate parameter types match the macro invocation.
- Inspect logs for errors during command resolution.
- Filters not applying:
- Ensure the filter is registered and enabled.
- Review filter conditions and configuration options.
- Test with minimal logic to isolate issues.
- UI updates not appearing:
- Marshal UI updates onto the correct thread using the dispatcher.
- Avoid long-running operations on the UI thread.
**Section sources**
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [Filters.cs](file://ClassicAssist.Shared/Engine/Filters.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
## Conclusion
ClassicAssist.Avalonia’s plugin architecture leverages attribute-based discovery and manager-driven orchestration to provide a flexible extensibility model. Developers can add macro commands, hotkey bindings, and filters with minimal boilerplate. By following the guidelines for lifecycle management, dependency injection, and security, you can build robust, maintainable plugins that integrate seamlessly with the host application.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
### Guidelines for Plugin Development and Distribution
- Naming and organization:
- Use clear namespaces and assembly names for plugins.
- Keep related commands and filters grouped logically.
- Attributes and contracts:
- Follow established attribute conventions for discovery.
- Implement interfaces consistently to ensure compatibility.
- Configuration:
- Provide user-friendly titles and descriptions for filter options.
- Persist settings securely and validate inputs.
- Testing:
- Unit test filter logic and macro commands.
- Simulate hotkey events to verify bindings.
- Distribution:
- Package plugins as separate assemblies.
- Include documentation and version information.
- Provide installation instructions and compatibility notes.
[No sources needed since this section provides general guidance]