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,378 @@
# Cross-Platform Considerations
<cite>
**Referenced Files in This Document**
- [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)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
- [ClassicAssist.Avalonia.csproj](file://ClassicAssist.Avalonia/ClassicAssist.Avalonia.csproj)
- [ClassicAssist.csproj](file://ClassicAssist/ClassicAssist.csproj)
</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 cross-platform implementation strategy for ClassicAssist.Avalonia, focusing on how platform-specific functionality is abstracted and resolved at runtime. It covers:
- Platform abstraction layer design using interfaces such as IDispatcher and IUIInvoker
- Platform detection and conditional compilation strategies
- File system abstraction, path handling, and configuration management
- Threading model differences across Windows, macOS, and Linux
- Native interop considerations for platform-specific APIs
- Deployment, packaging, and build configurations
- Performance optimization techniques per target platform and .NET runtime behavior
## Project Structure
The project separates shared logic from UI implementations:
- Shared abstractions and platform detection live in ClassicAssist.Shared
- Avalonia-based UI and its platform-specific dispatching live in ClassicAssist.Avalonia
- WPF-based UI and its platform-specific dispatching live in ClassicAssist (legacy)
```mermaid
graph TB
subgraph "Shared"
A["IDispatcher.cs"]
B["IUIInvoker.cs"]
C["PlatformDetector.cs"]
D["NativeMethods.cs"]
end
subgraph "Avalonia UI"
E["AvaloniaDispatcher.cs"]
F["AvaloniaUIInvoker.cs"]
G["Engine.cs"]
H["Program.cs"]
I["App.axaml.cs"]
end
subgraph "WPF UI (Legacy)"
J["WPFDispatcher.cs"]
K["WPFUIInvoker.cs"]
end
A --> E
B --> F
C --> G
D --> G
E --> G
F --> G
H --> G
I --> G
A --> J
B --> K
```
**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)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.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)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
## Core Components
- IDispatcher: Abstraction for scheduling work onto the UI thread. Implementations exist for Avalonia and WPF to ensure UI updates are marshaled correctly on each platform.
- IUIInvoker: Abstraction for UI-level operations that require platform-specific calls (e.g., message boxes, window interactions). Implementations encapsulate platform details behind a common interface.
- PlatformDetector: Provides runtime OS detection used by engine initialization and feature toggles.
- Engine (Avalonia): Bootstraps the application, resolves dispatcher and invoker, initializes services, and starts the UI loop.
- Program and App: Entry points that configure the Avalonia application lifecycle and resolve DI or static services.
Key responsibilities:
- Decouple UI threading and UI invocation from core logic
- Centralize platform detection and native interop usage
- Provide consistent initialization across platforms
**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)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
## Architecture Overview
The architecture uses an inversion-of-control pattern where the shared core depends only on interfaces. The UI layer provides concrete implementations selected at startup.
```mermaid
classDiagram
class IDispatcher {
+Invoke(action) void
+BeginInvoke(action) void
}
class IUIInvoker {
+ShowMessage(text) void
+OpenFile() string
+SaveFile(data) bool
}
class AvaloniaDispatcher
class AvaloniaUIInvoker
class WPFDispatcher
class WPFUIInvoker
IDispatcher <|.. AvaloniaDispatcher
IDispatcher <|.. WPFDispatcher
IUIInvoker <|.. AvaloniaUIInvoker
IUIInvoker <|.. WPFUIInvoker
```
**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)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
## Detailed Component Analysis
### Dispatcher Abstraction and Implementations
Purpose:
- Ensure all UI-related work runs on the correct UI thread regardless of platform.
- Provide BeginInvoke and Invoke semantics compatible with Avalonia and WPF.
Design:
- IDispatcher defines the contract.
- AvaloniaDispatcher implements it using Avalonia’s dispatcher primitives.
- WPFDispatcher implements it using WPF’s dispatcher primitives.
```mermaid
sequenceDiagram
participant Core as "Core Logic"
participant Disp as "IDispatcher"
participant Impl as "AvaloniaDispatcher"
participant UI as "Avalonia UI Thread"
Core->>Disp : "Invoke(updateUI)"
Disp->>Impl : "Dispatch call"
Impl->>UI : "Marshal to UI thread"
UI-->>Core : "Update completed"
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
### UI Invoker Abstraction and Implementations
Purpose:
- Encapsulate UI operations that differ between platforms (message boxes, file dialogs, window behaviors).
- Keep core logic free of platform-specific UI code.
Design:
- IUIInvoker defines the contract.
- AvaloniaUIInvoker and WPFUIInvoker implement platform-specific calls.
```mermaid
sequenceDiagram
participant Core as "Core Logic"
participant Inv as "IUIInvoker"
participant Impl as "AvaloniaUIInvoker"
participant OS as "OS Dialogs"
Core->>Inv : "ShowMessage(text)"
Inv->>Impl : "Forward to platform impl"
Impl->>OS : "Invoke native dialog"
OS-->>Impl : "Result"
Impl-->>Core : "Return"
```
**Diagram sources**
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
**Section sources**
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
### Platform Detection and Conditional Compilation
Purpose:
- Detect runtime OS to enable/disable features or choose paths/configurations.
- Support compile-time flags for platform-specific builds.
Behavior:
- PlatformDetector exposes OS information consumed by Engine and other components.
- Build targets may use conditional compilation to include/exclude platform-specific assets or code paths.
```mermaid
flowchart TD
Start(["Application Start"]) --> Detect["Detect OS via PlatformDetector"]
Detect --> IsWindows{"Is Windows?"}
IsWindows --> |Yes| WinPath["Use Windows paths and settings"]
IsWindows --> |No| IsMac{"Is macOS?"}
IsMac --> |Yes| MacPath["Use macOS paths and settings"]
IsMac --> |No| LinuxPath["Use Linux paths and settings"]
WinPath --> Init["Initialize services"]
MacPath --> Init
LinuxPath --> Init
Init --> End(["Ready"])
```
**Diagram sources**
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
**Section sources**
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
### File System Abstraction and Path Handling
Guidelines:
- Use platform-aware path utilities to construct directories and files consistently.
- Prefer environment variables and well-known locations for user data and configuration.
- Normalize separators and handle case sensitivity differences on Linux/macOS.
Recommendations:
- Centralize path resolution in a small helper module that wraps System.IO and Environment APIs.
- Abstract read/write operations behind simple methods to allow mocking in tests.
[No sources needed since this section provides general guidance]
### Configuration Management
Guidelines:
- Store user preferences in platform-appropriate locations (e.g., Application Data on Windows, ~/Library on macOS, ~/.config on Linux).
- Serialize settings to JSON or XML; validate schema on load.
- Provide defaults and migration helpers when configuration formats change.
[No sources needed since this section provides general guidance]
### Threading Model Differences
- Windows: WPF uses a single-threaded apartment model for UI threads; Avalonia uses a different threading model based on its rendering backend.
- macOS: Avalonia integrates with Cocoa; ensure UI updates occur on the main run loop thread.
- Linux: Avalonia uses X11/Wayland backends; marshal UI updates appropriately.
Best practices:
- Always route UI updates through IDispatcher.
- Avoid blocking the UI thread; offload long-running tasks to background threads.
- Be mindful of synchronization primitives and avoid deadlocks when crossing UI boundaries.
[No sources needed since this section provides general guidance]
### Native Interop Considerations
- Use P/Invoke sparingly and wrap calls in safe abstractions.
- Guard calls with PlatformDetector checks to avoid unsupported scenarios.
- Handle exceptions from native calls and map them to user-friendly messages via IUIInvoker.
- Consider loading native libraries conditionally based on OS and architecture.
**Section sources**
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
### Application Bootstrap and Service Resolution
Flow:
- Program sets up the Avalonia application.
- App configures resources and resolves services.
- Engine initializes platform detection, dispatcher, invoker, and core subsystems.
```mermaid
sequenceDiagram
participant Proc as "Program.cs"
participant App as "App.axaml.cs"
participant Eng as "Engine.cs"
participant Det as "PlatformDetector.cs"
participant Disp as "IDispatcher"
participant Inv as "IUIInvoker"
Proc->>App : "Create and configure Avalonia app"
App->>Eng : "Initialize engine"
Eng->>Det : "Detect OS"
Eng->>Disp : "Resolve dispatcher"
Eng->>Inv : "Resolve UI invoker"
Eng-->>Proc : "Start UI loop"
```
**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)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.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)
## Dependency Analysis
High-level dependencies:
- ClassicAssist.Avalonia depends on ClassicAssist.Shared for abstractions and platform detection.
- ClassicAssist (WPF) also depends on ClassicAssist.Shared but provides WPF-specific implementations.
- Both UI projects depend on their respective UI frameworks (Avalonia vs WPF).
```mermaid
graph LR
Shared["ClassicAssist.Shared"]
Avalonia["ClassicAssist.Avalonia"]
WPF["ClassicAssist (WPF)"]
Shared --> Avalonia
Shared --> WPF
```
**Diagram sources**
- [ClassicAssist.Avalonia.csproj](file://ClassicAssist.Avalonia/ClassicAssist.Avalonia.csproj)
- [ClassicAssist.csproj](file://ClassicAssist/ClassicAssist.csproj)
**Section sources**
- [ClassicAssist.Avalonia.csproj](file://ClassicAssist.Avalonia/ClassicAssist.Avalonia.csproj)
- [ClassicAssist.csproj](file://ClassicAssist/ClassicAssist.csproj)
## Performance Considerations
- UI Threading: Minimize work on the UI thread; batch updates and coalesce frequent changes.
- Rendering: On macOS and Linux, prefer vector graphics and avoid heavy bitmap operations on the UI thread.
- I/O: Use asynchronous file operations and cache frequently accessed data.
- GC Pressure: Reuse buffers and objects where possible; avoid allocations in hot loops.
- Native Calls: Batch native calls and reduce marshaling overhead by passing arrays instead of scalars.
- Runtime: On .NET 6+, leverage modern runtime optimizations and consider ReadyToRun for faster cold starts.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and remedies:
- UI not updating: Ensure all UI modifications go through IDispatcher.
- Crashes on native calls: Wrap P/Invoke in try/catch and verify OS/arch compatibility before calling.
- Incorrect paths: Validate path construction with PlatformDetector and normalize separators.
- Deadlocks: Review cross-thread synchronization and avoid nested UI locks.
**Section sources**
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
## Conclusion
ClassicAssist.Avalonia achieves cross-platform consistency by isolating platform-specific concerns behind clear interfaces (IDispatcher, IUIInvoker), centralizing platform detection, and providing targeted implementations per UI framework. This design simplifies maintenance, enables testing, and supports future platform additions while preserving performance and reliability across Windows, macOS, and Linux.
@@ -0,0 +1,343 @@
# Engine Lifecycle Management
<cite>
**Referenced Files in This Document**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.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 ClassicAssist.Avalonia engine lifecycle management system, focusing on initialization from application startup through game connection establishment, shutdown procedures, and cross-platform UI dispatching. It covers the Engine class architecture, configuration loading, dependency injection setup, startup phases (core initialization, plugin discovery, UI framework setup, network activation), graceful shutdown, error recovery, health monitoring, and diagnostic logging.
## Project Structure
The Avalonia-based entry point initializes the UI framework and constructs the Engine instance. The shared Engine provides core orchestration, while platform-specific components implement UI threading and invoker abstractions.
```mermaid
graph TB
Program["Program.cs"] --> App["App.axaml.cs"]
App --> EngineAvalonia["Engine.cs (Avalonia)"]
EngineAvalonia --> SharedEngine["Engine.cs (Shared)"]
EngineAvalonia --> Dispatcher["AvaloniaDispatcher.cs"]
EngineAvalonia --> UIInvoker["AvaloniaUIInvoker.cs"]
Dispatcher -.implements.-> IDisp["IDispatcher.cs"]
UIInvoker -.implements.-> IUIInv["IUIInvoker.cs"]
```
**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)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.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)
- [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)
## Core Components
- Avalonia Engine: Platform-specific orchestrator that wires up UI, configuration, plugins, and networking for the Avalonia runtime.
- Shared Engine: Cross-platform core that manages lifecycle phases, services, and coordination between subsystems.
- Dispatcher abstraction: Provides a consistent way to marshal work onto the UI thread across platforms.
- UI Invoker abstraction: Encapsulates UI operations such as showing dialogs or updating UI state.
Key responsibilities:
- Construct and configure the Engine with dependencies.
- Load configuration and profiles.
- Discover and initialize plugins.
- Initialize UI framework and main window.
- Start network layer and establish game connection.
- Provide graceful shutdown with resource cleanup and session persistence.
- Route asynchronous work via dispatcher and handle errors robustly.
**Section sources**
- [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)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
## Architecture Overview
The lifecycle is orchestrated by the Avalonia Engine, which composes shared services and platform-specific implementations. Initialization proceeds through well-defined phases, and shutdown reverses them safely.
```mermaid
sequenceDiagram
participant OS as "Operating System"
participant Program as "Program.cs"
participant App as "App.axaml.cs"
participant Engine as "Engine.cs (Avalonia)"
participant SharedEng as "Engine.cs (Shared)"
participant Disp as "AvaloniaDispatcher.cs"
participant UIInv as "AvaloniaUIInvoker.cs"
OS->>Program : Launch process
Program->>App : Configure and run Avalonia app
App->>Engine : Create Engine instance
Engine->>SharedEng : Initialize core services
Engine->>Engine : Load configuration and profiles
Engine->>Engine : Discover and load plugins
Engine->>Disp : Set up dispatcher for UI thread
Engine->>UIInv : Register UI invoker
Engine->>Engine : Initialize UI framework and main window
Engine->>Engine : Activate network layer
Engine->>Engine : Establish game connection
Note over Engine,SharedEng : Application ready
Engine-->>SharedEng : On shutdown requested
SharedEng-->>Engine : Cleanup resources and save session
Engine-->>App : Exit gracefully
```
**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)
## Detailed Component Analysis
### Engine Class Architecture (Avalonia)
Responsibilities:
- Constructor parameters include configuration sources, service providers, and optional overrides for testing.
- Dependency injection setup registers core services, UI components, and platform-specific implementations.
- Configuration loading reads settings and profile data before other subsystems start.
- Plugin discovery scans assemblies and loads compatible modules.
- UI framework setup initializes Avalonia, themes, and the main window.
- Network activation starts packet handling and connection management.
Lifecycle hooks:
- Pre-initialization: validate environment and prerequisites.
- Post-initialization: finalize UI and network readiness.
- Shutdown: persist session, release resources, stop background tasks.
Error handling:
- Centralized try/catch around major phases with diagnostic logging.
- Fallback behaviors when optional features fail to load.
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
### Shared Engine Orchestration
Responsibilities:
- Coordinates phase transitions and ensures ordered startup/shutdown.
- Exposes health status and diagnostics for monitoring.
- Manages long-running services and their lifetimes.
- Provides APIs for plugins and subsystems to register handlers and callbacks.
Health monitoring:
- Periodic checks for critical subsystems (network, UI, storage).
- Aggregated health report accessible to UI and diagnostics.
Diagnostics:
- Structured logging with severity levels and contextual metadata.
- Event-driven telemetry points at key lifecycle transitions.
**Section sources**
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Dispatcher System (Cross-Platform UI Threading)
Purpose:
- Abstracts UI thread marshaling behind a single interface.
- Ensures all UI updates occur on the correct thread regardless of platform.
Implementation highlights:
- AvaloniaDispatcher implements IDispatcher using Avalonia’s dispatcher.
- Methods to schedule work on UI thread and check current thread context.
- Thread-safe queuing for high-frequency UI updates.
Usage patterns:
- Network and background threads use dispatcher to update UI state.
- Plugins invoke dispatcher to interact with UI safely.
**Section sources**
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
### UI Invoker Abstraction
Purpose:
- Encapsulates UI operations like showing dialogs, notifications, and message boxes.
- Allows swapping implementations per platform without changing business logic.
Implementation highlights:
- AvaloniaUIInvoker implements IUIInvoker for Avalonia.
- Provides methods aligned with common UI interactions required by the engine and plugins.
**Section sources**
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
### Startup Phases
- Core initialization: construct shared services, set up logging, and prepare configuration.
- Plugin discovery: scan and load plugins; validate compatibility and register capabilities.
- UI framework setup: initialize Avalonia, apply themes, create main window, bind view models.
- Network layer activation: start packet filters/handlers, connect to game server, synchronize state.
```mermaid
flowchart TD
Start(["Application Start"]) --> CoreInit["Core Initialization"]
CoreInit --> ConfigLoad["Load Configuration and Profiles"]
ConfigLoad --> PluginDiscovery["Discover and Load Plugins"]
PluginDiscovery --> UISetup["Initialize UI Framework and Main Window"]
UISetup --> NetActivate["Activate Network Layer"]
NetActivate --> GameConnect["Establish Game Connection"]
GameConnect --> Ready(["Ready"])
```
**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)
### Graceful Shutdown Procedures
Steps:
- Signal subsystems to stop accepting new work.
- Persist session and user preferences.
- Release file handles, network sockets, and timers.
- Unsubscribe from events and dispose services.
- Exit the process cleanly.
```mermaid
flowchart TD
Requested(["Shutdown Requested"]) --> StopAccepting["Stop Accepting New Work"]
StopAccepting --> SaveSession["Save Session and Preferences"]
SaveSession --> ReleaseResources["Release Resources and Timers"]
ReleaseResources --> Unsubscribe["Unsubscribe Events and Dispose Services"]
Unsubscribe --> ExitProcess["Exit Process"]
```
**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)
### Error Recovery Mechanisms
Strategies:
- Phase-level isolation so failures in one area do not crash the entire engine.
- Retry policies for transient network issues during connection establishment.
- Fallback defaults when configuration or plugin loading fails.
- Health checks trigger automatic recovery attempts where safe.
Logging:
- Diagnostic logs capture stack traces, context, and timestamps.
- Severity levels allow filtering for production vs. development.
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Health Monitoring and Diagnostics
- Health endpoints expose status of core subsystems (UI, network, storage).
- Periodic probes detect degraded states and log warnings.
- Diagnostics provide snapshots of active services and recent events.
**Section sources**
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
## Dependency Analysis
The Avalonia Engine depends on shared orchestration and platform-specific UI components. The dispatcher and UI invoker are abstracted to keep platform concerns isolated.
```mermaid
classDiagram
class Engine_Avalonia {
+Configure()
+Start()
+Shutdown()
-LoadConfiguration()
-DiscoverPlugins()
-SetupUI()
-ActivateNetwork()
}
class Engine_Shared {
+RunPhases()
+GetHealthStatus()
+LogDiagnostic()
-ManageServices()
}
class AvaloniaDispatcher {
+InvokeOnUIThread(action)
+CheckUIThread()
}
class AvaloniaUIInvoker {
+ShowDialog(message)
+ShowMessage(text)
}
class IDispatcher
class IUIInvoker
Engine_Avalonia --> Engine_Shared : "orchestrates"
Engine_Avalonia --> AvaloniaDispatcher : "uses"
Engine_Avalonia --> AvaloniaUIInvoker : "uses"
AvaloniaDispatcher ..|> IDispatcher : "implements"
AvaloniaUIInvoker ..|> IUIInvoker : "implements"
```
**Diagram sources**
- [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)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
**Section sources**
- [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)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
## Performance Considerations
- Defer heavy initialization until after UI is visible to reduce startup latency.
- Batch UI updates via the dispatcher to avoid excessive reflows.
- Use async/await for network operations and disk I/O to keep UI responsive.
- Limit plugin scanning scope and cache discovered types to speed up repeated startups.
- Employ health probes with reasonable intervals to avoid overhead.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- UI thread violations: ensure all UI updates go through the dispatcher; verify CheckUIThread usage.
- Network connection failures: inspect diagnostic logs for retry attempts and error codes; confirm server reachability.
- Plugin load errors: validate assembly compatibility and missing dependencies; review plugin discovery logs.
- Configuration problems: check for malformed files and fallback behavior; verify profile paths.
- Shutdown hangs: identify uncompleted tasks or subscriptions; ensure proper disposal order.
**Section sources**
- [Engine.cs](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
## Conclusion
The ClassicAssist.Avalonia engine lifecycle is structured around clear phases, robust error handling, and platform abstraction. The Avalonia Engine coordinates shared services, configuration, plugins, UI, and networking, while the dispatcher and UI invoker isolate platform specifics. Health monitoring and diagnostics support reliable operation and troubleshooting throughout the lifecycle.
@@ -0,0 +1,352 @@
# Entity System Architecture
<cite>
**Referenced Files in This Document**
- [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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [ItemCollection.cs](file://ClassicAssist.Shared/UO/Objects/ItemCollection.cs)
- [MobileCollection.cs](file://ClassicAssist.Shared/UO/Objects/MobileCollection.cs)
- [GumpCollection.cs](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs)
- [Property.cs](file://ClassicAssist.Shared/UO/Objects/Property.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.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 ClassicAssist.Avalonia entity system architecture with a focus on:
- The Entity base class hierarchy and shared properties/methods/events
- Mobile implementation for player characters, NPCs, creatures, and movement systems
- Item object model including inventory items, equipment slots, container hierarchies, and property systems
- Gump rendering system for interactive UI elements and dialog boxes
- Entity collection management, filtering, sorting, and performance optimization strategies
- Entity lifecycle events, state synchronization between client and server, and memory management considerations
The goal is to make the system understandable for both new contributors and experienced developers while providing actionable guidance for extension and maintenance.
## Project Structure
The entity system lives primarily under ClassicAssist.Shared/UO/Objects and related subfolders. Key areas include:
- Core entities: Entity, Mobile, PlayerMobile, Item
- Collections: EntityCollection, MobileCollection, ItemCollection, GumpCollection
- UI layer: Gumps and associated collections
- Properties: Property model used by Items and other objects
```mermaid
graph TB
subgraph "UO Objects"
E["Entity"]
M["Mobile"]
PM["PlayerMobile"]
I["Item"]
P["Property"]
EC["EntityCollection"]
MC["MobileCollection"]
IC["ItemCollection"]
GC["GumpCollection"]
end
subgraph "Gumps"
G["Gump"]
GP["GumpPage"]
GE["GumpElement"]
end
E --> M
M --> PM
E --> I
I --> P
EC --> E
MC --> M
IC --> I
GC --> G
G --> GP
GP --> GE
```
[No sources needed since this diagram shows conceptual workflow, not actual code structure]
## Core Components
- Entity base class provides common identity, location, visibility, and lifecycle hooks used across all game objects.
- Mobile extends Entity to represent living beings (players, NPCs, creatures) with movement, targeting, and combat-related behavior.
- Item extends Entity to represent world and inventory objects, containers, equipment, and dynamic properties.
- Gump represents interactive UI windows and pages, with elements that respond to user input.
- Collections manage sets of entities with efficient lookup, filtering, and iteration.
Key responsibilities:
- Identity and lifetime management
- Spatial coordinates and map context
- Event-driven updates and notifications
- Network synchronization points
- UI integration via gumps and bindings
**Section sources**
- [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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [ItemCollection.cs](file://ClassicAssist.Shared/UO/Objects/ItemCollection.cs)
- [MobileCollection.cs](file://ClassicAssist.Shared/UO/Objects/MobileCollection.cs)
- [GumpCollection.cs](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs)
- [Property.cs](file://ClassicAssist.Shared/UO/Objects/Property.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
## Architecture Overview
The entity system follows a layered design:
- Base layer: Entity defines universal attributes and behaviors
- Specialized layers: Mobile and Item inherit from Entity and add domain-specific features
- UI layer: Gumps provide interactive overlays and dialogs
- Collection layer: Typed collections optimize storage, lookup, and queries
```mermaid
classDiagram
class Entity {
+Id
+Map
+X
+Y
+Z
+Visible
+OnCreated()
+OnUpdated()
+OnRemoved()
}
class Mobile {
+Hue
+Body
+Name
+Direction
+Speed
+Target
+MoveTo(target)
+UpdateMovement()
}
class PlayerMobile {
+Skills
+Stats
+Equipment
+Inventory
}
class Item {
+Serial
+Layer
+Stackable
+Properties
+Container
+Use()
+Inspect()
}
class Gump {
+PageCount
+Show()
+Hide()
+HandleClick(button)
}
class GumpPage
class GumpElement
class Property
Entity <|-- Mobile
Mobile <|-- PlayerMobile
Entity <|-- Item
Item --> Property : "has many"
Gump --> GumpPage : "contains"
GumpPage --> GumpElement : "contains"
```
**Diagram sources**
- [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)
- [Property.cs](file://ClassicAssist.Shared/UO/Objects/Property.cs)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
## Detailed Component Analysis
### Entity Base Class Hierarchy
Common responsibilities:
- Unique identification and association with maps and locations
- Visibility flags and update cycles
- Lifecycle hooks for creation, updates, and removal
- Event emission for subscribers (e.g., position changes, visibility toggles)
Shared properties typically include:
- Identifier fields for network and local tracking
- Map and coordinate fields for spatial queries
- Flags for visibility and active state
- Timestamps or versioning for synchronization
Event patterns:
- OnCreated/OnUpdated/OnRemoved for lifecycle
- PropertyChanged-style notifications for key attributes
- Custom events for movement, targeting, and interaction
Optimization notes:
- Avoid heavy work in event handlers; prefer batching where possible
- Use weak references for listeners to prevent leaks
- Coalesce frequent updates (e.g., position deltas) before notifying
**Section sources**
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
### Mobile Implementation
Mobile models living entities such as players, NPCs, and creatures. It adds:
- Appearance: hue, body type, name
- Movement: direction, speed, pathfinding integration
- Targeting: current target, auto-target logic
- Combat state: aggression flags, status effects (via properties)
Movement system:
- Requests movement through packet-based commands
- Interpolates or applies server-authoritative positions
- Integrates with pathfinding to avoid obstacles
- Handles mount states and special movement modes
Lifecycle and sync:
- Incoming packets update mobile state
- Outgoing requests initiate actions (move, attack, use skill)
- Local prediction may be used for responsiveness, reconciled with server state
**Section sources**
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
### Item Object Model
Item represents physical and virtual objects:
- World items and inventory items
- Containers and nested hierarchies
- Equipment slots and layer associations
- Dynamic properties and custom data
Key concepts:
- Serial and parent/container relationships define ownership
- Layer indicates equipment slot when equipped
- Stackable flag supports quantity semantics
- Property list enables rich metadata and UI binding
Container hierarchies:
- Parent-child relationships form trees
- Updates propagate content changes efficiently
- Bulk operations minimize packet overhead
Property systems:
- Standard properties (name, description, stats)
- Custom properties for modding and automation
- Batched property queries reduce network traffic
**Section sources**
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
- [Property.cs](file://ClassicAssist.Shared/UO/Objects/Property.cs)
### Gump Rendering System
Gumps provide interactive UI overlays:
- Pages and elements compose complex interfaces
- Click and input handling routes to application logic
- Show/hide lifecycle integrates with window managers
Rendering and interaction:
- Elements are laid out per page
- Events bubble up to gump handlers
- Binding to entity/item properties drives dynamic UI
Best practices:
- Keep gumps lightweight; offload heavy tasks to background threads
- Reuse gump instances where possible
- Debounce rapid user interactions
**Section sources**
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
### Entity Collection Management
Collections provide optimized storage and querying:
- EntityCollection manages generic entities
- MobileCollection and ItemCollection specialize for typed access
- GumpCollection manages UI overlays
Features:
- Fast lookup by ID or serial
- Filtering by criteria (type, map, range, tags)
- Sorting by attributes (distance, name, timestamp)
- Efficient iteration for rendering and updates
Performance strategies:
- Indexes for frequently queried fields
- Lazy evaluation for filters and sorts
- Batching updates to reduce churn
- Memory pooling for transient query results
**Section sources**
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [MobileCollection.cs](file://ClassicAssist.Shared/UO/Objects/MobileCollection.cs)
- [ItemCollection.cs](file://ClassicAssist.Shared/UO/Objects/ItemCollection.cs)
- [GumpCollection.cs](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs)
## Dependency Analysis
High-level dependencies:
- Mobile and Item depend on Entity for core functionality
- PlayerMobile specializes Mobile for player-specific data
- Item uses Property for metadata and dynamic values
- Gumps interact with Entities and Items via bindings and commands
- Collections depend on their respective entity types for indexing and queries
```mermaid
graph LR
Entity --> Mobile
Mobile --> PlayerMobile
Entity --> Item
Item --> Property
EntityCollection --> Entity
MobileCollection --> Mobile
ItemCollection --> Item
GumpCollection --> Gump
Gump --> Entity
Gump --> Item
```
**Diagram sources**
- [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)
- [Property.cs](file://ClassicAssist.Shared/UO/Objects/Property.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [MobileCollection.cs](file://ClassicAssist.Shared/UO/Objects/MobileCollection.cs)
- [ItemCollection.cs](file://ClassicAssist.Shared/UO/Objects/ItemCollection.cs)
- [GumpCollection.cs](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
## Performance Considerations
- Update batching: Group multiple entity updates into fewer notifications to reduce UI churn.
- Spatial queries: Use distance checks and bounding regions to limit expensive calculations.
- Property caching: Cache computed or remote property values with invalidation on change.
- Collection indexes: Maintain secondary indexes for hot paths (e.g., nearest neighbor).
- Event coalescing: Merge rapid successive events (position, visibility) before dispatch.
- Memory management: Clear references in removal hooks; avoid retaining large temporary structures.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- Stale entity state: Ensure incoming packet handlers reconcile local predictions with authoritative server updates.
- Missing properties: Verify batched property queries complete and cache invalidation occurs on updates.
- UI lag: Offload heavy computations from UI thread; debounce user inputs; reuse gump instances.
- Memory growth: Check for lingering event subscriptions; ensure removal hooks release resources.
- Container inconsistencies: Validate parent-child relationships after bulk updates; rebuild indices if necessary.
**Section sources**
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [Item.cs](file://ClassicAssist.Shared/UO/Objects/Item.cs)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
## Conclusion
The ClassicAssist.Avalonia entity system centers around a clean base Entity class extended by Mobile and Item, with robust collections and a flexible gump UI layer. By leveraging event-driven updates, efficient collections, and careful memory management, the system scales to handle thousands of entities and responsive UIs. Following the patterns outlined here will help maintain performance and correctness as the system evolves.
@@ -0,0 +1,406 @@
# Event-Driven 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)
- [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)
- [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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [ChatViewModel.cs](file://ClassicAssist/Engine/ViewModels/ChatViewModel.cs)
- [ThreadQueue.cs](file://ClassicAssist.Shared/Misc/ThreadQueue.cs)
- [ThreadPriorityQueue.cs](file://ClassicAssist.Shared/Misc/ThreadPriorityQueue.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 event-driven architecture used by ClassicAssist.Avalonia to achieve loose coupling between network, engine, and UI layers. It focuses on how events are published and subscribed across components, how game state changes propagate via MVVM to update the UI, and how packet events flow from the network layer through the game engine to UI updates. It also covers custom event creation, routing, priority-based processing, thread safety for cross-thread handling, and performance optimization techniques for high-frequency events such as packet processing and entity updates.
## Project Structure
The event-driven system spans multiple projects:
- Shared networking and engine logic (Shared project)
- Avalonia UI application (Avalonia project)
- WPF legacy bridge (ClassicAssist project)
- ViewModels and UI models (Shared UI folder)
```mermaid
graph TB
subgraph "Shared"
Net["Network Layer<br/>Packets, Handlers, Queues"]
Eng["Game Engine<br/>Entities, Collections"]
UIModel["UI Models & ViewModels"]
end
subgraph "Avalonia"
App["App & Engine Entry"]
Disp["Avalonia Dispatcher"]
end
subgraph "WPF Bridge"
WDisp["WPF Dispatcher"]
end
Net --> Eng
Eng --> UIModel
UIModel --> App
App --> Disp
App --> WDisp
```
[No sources needed since this diagram shows conceptual workflow, not actual code structure]
## Core Components
- Network packet handlers and queues manage incoming/outgoing packets and route them into the engine.
- Game engine entities expose state that is observed by view models.
- View models implement MVVM and subscribe to engine state changes.
- Dispatchers and UI invokers marshal UI updates onto the UI thread safely.
Key responsibilities:
- IncomingPacketHandlers and OutgoingPacketHandlers register and dispatch packet-specific logic.
- ActionPacketQueue batches and prioritizes actions for efficient processing.
- Entity and Mobile classes represent game objects; collections aggregate them.
- BaseViewModel provides common MVVM infrastructure; MainWindowViewModel orchestrates UI state.
- AvaloniaDispatcher and AvaloniaUIInvoker coordinate UI thread synchronization.
**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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.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)
## Architecture Overview
The system uses an event-driven pipeline:
- Network receives packets and publishes typed events via handlers.
- Engine consumes these events to mutate entity state.
- UI subscribes to state changes or explicit events and updates views via MVVM.
- Cross-thread marshaling ensures UI updates occur on the UI thread.
```mermaid
sequenceDiagram
participant Net as "Network Layer"
participant Hdl as "Packet Handlers"
participant Q as "Action Packet Queue"
participant Eng as "Game Engine"
participant VM as "ViewModels"
participant UI as "Avalonia UI"
Net->>Hdl : "Incoming packet arrives"
Hdl->>Q : "Enqueue action/event"
Q-->>Eng : "Dequeue and process"
Eng->>Eng : "Update Entities/Collections"
Eng-->>VM : "State change notifications"
VM->>UI : "Invoke UI updates on UI thread"
UI-->>VM : "User interactions"
VM->>Net : "Outgoing commands/packets"
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
## Detailed Component Analysis
### Packet Event Handling Pipeline
The pipeline transforms raw network packets into structured engine updates and UI reactions.
```mermaid
flowchart TD
Start(["Packet Received"]) --> Parse["Parse Packet Type"]
Parse --> Route["Route to Handler"]
Route --> Enqueue["Enqueue Action/Event"]
Enqueue --> Process["Process Queue Item"]
Process --> UpdateState["Update Engine State"]
UpdateState --> Notify["Notify Subscribers"]
Notify --> Marshal["Marshal to UI Thread"]
Marshal --> End(["UI Updated"])
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
### Game State Propagation via MVVM
- Engine entities expose properties and collections that reflect current game state.
- View models observe these changes and raise property change notifications.
- UI binds to view model properties; dispatcher ensures updates run on the UI thread.
```mermaid
classDiagram
class Entity {
+Id
+Properties
+Update(...)
}
class Mobile {
+Position
+Status
}
class PlayerMobile {
+IsLocal
}
class EntityCollection {
+Add(...)
+Remove(...)
+FindById(...)
}
class BaseViewModel {
+RaisePropertyChanged(...)
}
class MainWindowViewModel {
+SelectedEntity
+ChatMessages
}
Mobile --|> Entity
PlayerMobile --|> Mobile
EntityCollection --> Entity : "manages"
MainWindowViewModel --> BaseViewModel : "extends"
MainWindowViewModel --> EntityCollection : "observes"
```
**Diagram sources**
- [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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
**Section sources**
- [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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
### Custom Event Creation and Routing
To create a new event type:
- Define a strongly-typed event payload class if needed.
- Register a handler in the appropriate packet handlers collection.
- Use the queue to enqueue the event/action with a priority if required.
- Ensure subscribers (engine modules or view models) listen for the event.
Routing considerations:
- Centralized registration points simplify discovery and testing.
- Priority-based queues allow critical events to be processed before less urgent ones.
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
### Priority-Based Event Processing
High-priority events (e.g., combat-related updates) should be enqueued with higher priority to ensure timely processing. Lower-priority events (e.g., cosmetic updates) can be batched or deferred.
```mermaid
flowchart TD
A["Enqueue Event"] --> B{"Has Priority?"}
B --> |Yes| C["Insert into Priority Queue"]
B --> |No| D["Append to Standard Queue"]
C --> E["Dequeue Highest Priority First"]
D --> E
E --> F["Process Event"]
```
**Diagram sources**
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [ThreadPriorityQueue.cs](file://ClassicAssist.Shared/Misc/ThreadPriorityQueue.cs)
**Section sources**
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [ThreadPriorityQueue.cs](file://ClassicAssist.Shared/Misc/ThreadPriorityQueue.cs)
### Thread Safety and UI Synchronization
Cross-thread event handling requires careful marshaling:
- Use IDispatcher and IUIInvoker abstractions to schedule work on the UI thread.
- Avoid direct UI updates from background threads.
- Prefer batching UI updates to reduce churn during high-frequency events.
```mermaid
sequenceDiagram
participant BG as "Background Thread"
participant Inv as "IUIInvoker"
participant Disp as "IDispatcher"
participant VM as "ViewModel"
participant UI as "Avalonia UI"
BG->>Inv : "Request UI update"
Inv->>Disp : "Dispatch to UI thread"
Disp-->>VM : "Invoke property change"
VM-->>UI : "Render updated bindings"
```
**Diagram sources**
- [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)
**Section sources**
- [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)
### High-Frequency Events: Packets and Entity Updates
Common high-frequency events include mobile updates and movement packets. To optimize:
- Coalesce rapid updates into fewer UI refreshes.
- Use immutable snapshots where possible to avoid excessive allocations.
- Apply filters to reduce unnecessary processing.
```mermaid
flowchart TD
Pkt["MobileUpdate/Moving Packet"] --> Filter["Apply Filters"]
Filter --> Batch["Batch Updates"]
Batch --> Apply["Apply to Entities"]
Apply --> Throttle["Throttle UI Notifications"]
Throttle --> Render["Render UI"]
```
**Diagram sources**
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
**Section sources**
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
### Application Entry Points and Initialization
The Avalonia application initializes core services, registers handlers, and starts the event loop.
```mermaid
sequenceDiagram
participant Main as "Program"
participant App as "App"
participant Eng as "Engine"
participant Net as "Network"
participant UI as "UI"
Main->>App : "Build and Run"
App->>Eng : "Initialize Engine"
Eng->>Net : "Start Network"
Net-->>Eng : "Incoming packets"
Eng-->>UI : "State changes"
UI-->>Eng : "User actions"
```
**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)
**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)
## Dependency Analysis
The following diagram highlights key dependencies among networking, engine, and UI components.
```mermaid
graph TB
IPH["IncomingPacketHandlers"] --> APQ["ActionPacketQueue"]
OPH["OutgoingPacketHandlers"] --> APQ
APQ --> ENG["Engine"]
ENG --> ENT["Entity/Mobile/PlayerMobile"]
ENG --> COL["EntityCollection"]
COL --> VM["MainWindowViewModel"]
VM --> UI["Avalonia UI"]
UI --> INV["AvaloniaUIInvoker"]
INV --> DISP["AvaloniaDispatcher"]
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
## Performance Considerations
- Batch and throttle UI updates to minimize layout passes.
- Use priority queues for critical events and defer low-priority tasks.
- Apply packet filters to reduce processing overhead.
- Prefer immutable snapshots for large data sets to reduce GC pressure.
- Avoid frequent allocations inside hot paths; reuse buffers when possible.
- Coalesce rapid entity updates into single notifications.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- UI not updating: Ensure UI invocations are dispatched on the UI thread using the dispatcher or UI invoker.
- Stuttering during high-frequency events: Implement batching and throttling for UI updates.
- Missed events: Verify handlers are registered and queues are being drained.
- Deadlocks: Avoid holding locks while invoking UI updates; keep UI work minimal.
**Section sources**
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
## Conclusion
ClassicAssist.Avalonia’s event-driven architecture enables loose coupling between network, engine, and UI layers. By leveraging typed packet handlers, priority queues, MVVM subscriptions, and robust UI thread marshaling, the system scales to handle high-frequency events efficiently. Following the patterns outlined here—custom event creation, careful routing, priority-based processing, and performance optimizations—will help maintain responsiveness and clarity as the application evolves.
@@ -0,0 +1,487 @@
# Game Engine
<cite>
**Referenced Files in This Document**
- [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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [GumpCollection.cs](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [ThreadQueue.cs](file://ClassicAssist.Shared/Misc/ThreadQueue.cs)
- [CircularBuffer.cs](file://ClassicAssist.Shared/Misc/CircularBuffer.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 describes the architectural design of the ClassicAssist.Avalonia game engine core, focusing on lifecycle management, entity system, event-driven synchronization, plugin and module registration, resource management, thread safety, and the game loop with frame rate control. It synthesizes information from the Avalonia UI layer, shared engine abstractions, and UO object model to provide a comprehensive view for both technical and non-technical readers.
## Project Structure
The project is organized into platform-specific UI layers (WPF and Avalonia) and a shared engine core that contains the game logic, networking, objects, and data managers. The Avalonia entry point initializes the application, resolves UI invokers and dispatchers, and starts the engine. The shared engine coordinates packet handling, macro execution, hotkeys, commands, and the main update loop.
```mermaid
graph TB
subgraph "Avalonia UI"
Program["Program.cs"]
App["App.axaml.cs"]
EngineAva["Engine.cs (Avalonia)"]
Dispatcher["AvaloniaDispatcher.cs"]
UIInvoker["AvaloniaUIInvoker.cs"]
end
subgraph "Shared Engine"
EngineShared["Engine.cs (Shared)"]
IDisp["IDispatcher.cs"]
IUIInv["IUIInvoker.cs"]
Incoming["IncomingPacketHandlers.cs"]
Queue["ActionPacketQueue.cs"]
MacroMgr["MacroManager.cs"]
HotkeyMgr["HotkeyManager.cs"]
CmdMgr["CommandsManager.cs"]
ThreadQ["ThreadQueue.cs"]
Circular["CircularBuffer.cs"]
end
subgraph "UO Objects"
Entity["Entity.cs"]
Mobile["Mobile.cs"]
Item["Item.cs"]
Gump["Gump.cs"]
GumpColl["GumpCollection.cs"]
end
Program --> App
App --> EngineAva
EngineAva --> Dispatcher
EngineAva --> UIInvoker
EngineAva --> EngineShared
EngineShared --> Incoming
EngineShared --> Queue
EngineShared --> MacroMgr
EngineShared --> HotkeyMgr
EngineShared --> CmdMgr
EngineShared --> ThreadQ
EngineShared --> Circular
EngineShared --> Entity
Entity --> Mobile
Entity --> Item
EngineShared --> Gump
EngineShared --> GumpColl
```
**Diagram sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [IDispatcher.cs:1-200](file://ClassicAssist.Shared/IDispatcher.cs#L1-L200)
- [IUIInvoker.cs:1-200](file://ClassicAssist.Shared/IUIInvoker.cs#L1-L200)
- [IncomingPacketHandlers.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L200)
- [ActionPacketQueue.cs:1-200](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [CommandsManager.cs:1-200](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs#L1-L200)
- [ThreadQueue.cs:1-200](file://ClassicAssist.Shared/Misc/ThreadQueue.cs#L1-L200)
- [CircularBuffer.cs:1-200](file://ClassicAssist.Shared/Misc/CircularBuffer.cs#L1-L200)
- [Entity.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Entity.cs#L1-L200)
- [Mobile.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Mobile.cs#L1-L200)
- [Item.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Item.cs#L1-L200)
- [Gump.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs#L1-L200)
- [GumpCollection.cs:1-200](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs#L1-L200)
**Section sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
## Core Components
- Application bootstrap and engine initialization are handled by the Avalonia program and app classes, which resolve UI threading primitives and start the shared engine.
- The shared engine orchestrates network packet processing, macro execution, hotkey handling, command routing, and the main update loop.
- The UO object model provides base entities, mobile characters, items, and gumps used throughout the game state and rendering pipeline.
- Threading utilities ensure safe cross-thread operations between the game loop and UI updates.
Key responsibilities:
- Lifecycle: startup, initialization of subsystems, main loop, graceful shutdown.
- Event-driven synchronization: incoming packets trigger handlers that update game state and notify UI via dispatcher/UI invoker.
- Plugin/module extension points: macro manager, hotkey manager, and command manager expose extensibility through attributes and registrations.
- Resource management: circular buffers and queues reduce allocations; UI updates are marshaled to avoid contention.
**Section sources**
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [IncomingPacketHandlers.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L200)
- [ActionPacketQueue.cs:1-200](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [CommandsManager.cs:1-200](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs#L1-L200)
- [ThreadQueue.cs:1-200](file://ClassicAssist.Shared/Misc/ThreadQueue.cs#L1-L200)
- [CircularBuffer.cs:1-200](file://ClassicAssist.Shared/Misc/CircularBuffer.cs#L1-L200)
## Architecture Overview
The engine follows a layered architecture:
- UI Layer (Avalonia): bootstraps the process, configures UI invoker and dispatcher, and hosts windows.
- Engine Core (Shared): manages lifecycle, packet processing, macros, hotkeys, commands, and the main loop.
- Object Model (UO): defines entities, mobiles, items, and gumps representing game state.
- Threading Abstractions: dispatcher and UI invoker decouple UI updates from game threads.
```mermaid
sequenceDiagram
participant OS as "Operating System"
participant Program as "Program.cs"
participant App as "App.axaml.cs"
participant EngineAva as "Engine.cs (Avalonia)"
participant EngineShared as "Engine.cs (Shared)"
participant Incoming as "IncomingPacketHandlers.cs"
participant UI as "AvaloniaUIInvoker.cs"
participant Disp as "AvaloniaDispatcher.cs"
OS->>Program : Launch process
Program->>App : Initialize Avalonia application
App->>EngineAva : Create engine instance
EngineAva->>EngineShared : Configure dispatcher and UI invoker
EngineAva->>EngineShared : Start engine (init subsystems)
EngineShared->>Incoming : Register packet handlers
EngineShared-->>EngineAva : Ready
EngineAva->>EngineShared : Enter main loop
Incoming-->>EngineShared : Packet events
EngineShared->>UI : Marshal UI updates
UI->>Disp : Invoke on UI thread
EngineShared-->>EngineAva : Shutdown requested
EngineAva->>EngineShared : Stop engine (cleanup)
```
**Diagram sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [IncomingPacketHandlers.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
## Detailed Component Analysis
### Engine Lifecycle Management
The engine lifecycle includes initialization, startup sequence, and graceful shutdown. Initialization sets up the dispatcher and UI invoker, registers packet handlers, and prepares subsystems. The startup sequence enters the main loop, processes packets, updates state, and renders UI. Graceful shutdown stops the loop, flushes pending work, and releases resources.
```mermaid
flowchart TD
Start(["Process Start"]) --> InitApp["Initialize Avalonia App"]
InitApp --> CreateEngine["Create Engine Instance"]
CreateEngine --> ConfigureThreading["Configure Dispatcher and UI Invoker"]
ConfigureThreading --> RegisterHandlers["Register Packet Handlers"]
RegisterHandlers --> PrepareSubsystems["Prepare Subsystems (Macros, Hotkeys, Commands)"]
PrepareSubsystems --> MainLoop["Enter Main Loop"]
MainLoop --> ProcessPackets["Process Incoming Packets"]
ProcessPackets --> UpdateState["Update Game State"]
UpdateState --> RenderUI["Marshal UI Updates"]
RenderUI --> CheckShutdown{"Shutdown Requested?"}
CheckShutdown --> |No| MainLoop
CheckShutdown --> |Yes| Cleanup["Cleanup Resources"]
Cleanup --> End(["Process Exit"])
```
**Diagram sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [IncomingPacketHandlers.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
**Section sources**
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
### Entity System Architecture
The entity system centers around a base class hierarchy:
- Entity: common properties and behaviors for all game objects.
- Mobile: represents living entities (players, NPCs), extending movement and combat-related features.
- Item: represents static or held objects with inventory and container semantics.
- Gump: UI overlays rendered over the game world, managed by a collection.
```mermaid
classDiagram
class Entity {
+int ID
+string Name
+int X
+int Y
+int Z
+bool IsValid()
+void Invalidate()
}
class Mobile {
+int Hue
+int Body
+Direction Direction
+bool IsMoving()
+void MoveTo(x, y, z)
}
class Item {
+int Hue
+int Layer
+bool IsEquipped()
+void Use()
}
class Gump {
+int ID
+string Title
+bool IsOpen()
+void Close()
}
class GumpCollection {
+Add(gump) void
+Remove(id) bool
+Get(id) Gump
+Clear() void
}
Entity <|-- Mobile
Entity <|-- Item
GumpCollection --> Gump : "manages"
```
**Diagram sources**
- [Entity.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Entity.cs#L1-L200)
- [Mobile.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Mobile.cs#L1-L200)
- [Item.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Item.cs#L1-L200)
- [Gump.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs#L1-L200)
- [GumpCollection.cs:1-200](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs#L1-L200)
**Section sources**
- [Entity.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Entity.cs#L1-L200)
- [Mobile.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Mobile.cs#L1-L200)
- [Item.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Item.cs#L1-L200)
- [Gump.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs#L1-L200)
- [GumpCollection.cs:1-200](file://ClassicAssist.Shared/UO/Objects/GumpCollection.cs#L1-L200)
### Event-Driven Architecture Patterns
Game state synchronization and UI updates are driven by packet events:
- IncomingPacketHandlers register handlers for specific packet types.
- Handlers update the entity system and collections.
- UI updates are marshaled via UI invoker and dispatcher to ensure thread safety.
- ActionPacketQueue batches actions to minimize UI churn.
```mermaid
sequenceDiagram
participant Net as "Network Layer"
participant Incoming as "IncomingPacketHandlers.cs"
participant Engine as "Engine.cs (Shared)"
participant Entities as "Entity/Mobile/Item"
participant UI as "AvaloniaUIInvoker.cs"
participant Disp as "AvaloniaDispatcher.cs"
Net->>Incoming : Deliver packet
Incoming->>Engine : Dispatch handler
Engine->>Entities : Update state (e.g., Mobile position)
Engine->>UI : Schedule UI update
UI->>Disp : Invoke on UI thread
Disp-->>UI : Execute UI update
```
**Diagram sources**
- [IncomingPacketHandlers.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [Entity.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Entity.cs#L1-L200)
- [Mobile.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Mobile.cs#L1-L200)
- [Item.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Item.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
**Section sources**
- [IncomingPacketHandlers.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L200)
- [ActionPacketQueue.cs:1-200](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
### Plugin Loading Mechanism and Module Registration
Extensibility is provided through:
- MacroManager: discovers and executes macro commands, exposing extension points via attributes.
- HotkeyManager: binds hotkeys to commands and actions.
- CommandsManager: routes user commands to registered handlers.
These components use reflection-based discovery and attribute-driven registration to allow plugins to add functionality without modifying core code.
```mermaid
flowchart TD
Start(["Engine Startup"]) --> ScanMacros["Scan Macro Commands"]
ScanMacros --> RegisterHotkeys["Register Hotkey Bindings"]
RegisterHotkeys --> RegisterCommands["Register Command Handlers"]
RegisterCommands --> Ready(["Extension Points Available"])
```
**Diagram sources**
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [CommandsManager.cs:1-200](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs#L1-L200)
**Section sources**
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [CommandsManager.cs:1-200](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs#L1-L200)
### Resource Management Strategies
Resource management focuses on minimizing allocations and optimizing garbage collection:
- CircularBuffer: reuses memory for streaming data like logs or packet buffers.
- ThreadQueue: provides efficient producer-consumer patterns for cross-thread work.
- UI updates are batched and marshaled to reduce contention and GC pressure.
```mermaid
flowchart TD
Allocate["Allocate Buffer"] --> Use["Use CircularBuffer"]
Use --> Reuse["Reuse Slots"]
Reuse --> Release["Release References"]
Allocate --> QueueWork["Enqueue Work via ThreadQueue"]
QueueWork --> Consume["Consume on Target Thread"]
Consume --> Clear["Clear Completed Items"]
```
**Diagram sources**
- [CircularBuffer.cs:1-200](file://ClassicAssist.Shared/Misc/CircularBuffer.cs#L1-L200)
- [ThreadQueue.cs:1-200](file://ClassicAssist.Shared/Misc/ThreadQueue.cs#L1-L200)
**Section sources**
- [CircularBuffer.cs:1-200](file://ClassicAssist.Shared/Misc/CircularBuffer.cs#L1-L200)
- [ThreadQueue.cs:1-200](file://ClassicAssist.Shared/Misc/ThreadQueue.cs#L1-L200)
### Thread Safety Considerations
Thread safety is enforced via:
- Dispatcher abstraction (IDispatcher) implemented by AvaloniaDispatcher to marshal UI updates.
- UI invoker (IUIInvoker) abstracting platform-specific invocation.
- Queues and buffers ensuring ordered, lock-free or low-contention operations.
```mermaid
classDiagram
class IDispatcher {
+Invoke(action) void
+BeginInvoke(action) void
}
class IUIInvoker {
+InvokeOnUiThread(action) void
}
class AvaloniaDispatcher {
+Invoke(action) void
+BeginInvoke(action) void
}
class AvaloniaUIInvoker {
+InvokeOnUiThread(action) void
}
IDispatcher <|.. AvaloniaDispatcher
IUIInvoker <|.. AvaloniaUIInvoker
```
**Diagram sources**
- [IDispatcher.cs:1-200](file://ClassicAssist.Shared/IDispatcher.cs#L1-L200)
- [IUIInvoker.cs:1-200](file://ClassicAssist.Shared/IUIInvoker.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
**Section sources**
- [IDispatcher.cs:1-200](file://ClassicAssist.Shared/IDispatcher.cs#L1-L200)
- [IUIInvoker.cs:1-200](file://ClassicAssist.Shared/IUIInvoker.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
### Game Loop Architecture and Frame Rate Management
The main loop runs continuously, processing packets, updating game state, and scheduling UI updates. Frame rate management is achieved by throttling updates and batching UI changes to maintain responsiveness while minimizing overhead.
```mermaid
flowchart TD
LoopStart(["Main Loop Entry"]) --> Tick["Frame Tick"]
Tick --> ProcessPackets["Process Packets"]
ProcessPackets --> UpdateEntities["Update Entities"]
UpdateEntities --> BatchUI["Batch UI Updates"]
BatchUI --> SleepOrYield["Sleep/Yield to Control FPS"]
SleepOrYield --> LoopStart
```
**Diagram sources**
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [ActionPacketQueue.cs:1-200](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs#L1-L200)
**Section sources**
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [ActionPacketQueue.cs:1-200](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs#L1-L200)
## Dependency Analysis
The engine’s dependencies are structured to separate concerns:
- UI layer depends on engine core for state and services.
- Engine core depends on networking, macros, hotkeys, commands, and object model.
- Object model is independent and consumed by engine and UI.
```mermaid
graph TB
UI["Avalonia UI"] --> EngineCore["Engine Core (Shared)"]
EngineCore --> Networking["Networking (Packets)"]
EngineCore --> Macros["Macro Manager"]
EngineCore --> Hotkeys["Hotkey Manager"]
EngineCore --> Commands["Command Manager"]
EngineCore --> Objects["UO Objects (Entity/Mobile/Item/Gump)"]
UI --> Threading["Dispatcher/UI Invoker"]
EngineCore --> Threading
```
**Diagram sources**
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [IncomingPacketHandlers.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [CommandsManager.cs:1-200](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs#L1-L200)
- [Entity.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Entity.cs#L1-L200)
- [Mobile.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Mobile.cs#L1-L200)
- [Item.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Item.cs#L1-L200)
- [Gump.cs:1-200](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs#L1-L200)
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
**Section sources**
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
## Performance Considerations
- Minimize allocations by using reusable buffers and queues.
- Batch UI updates to reduce marshaling overhead.
- Avoid frequent GC triggers by keeping short-lived objects minimal during hot paths.
- Throttle frame updates to balance responsiveness and CPU usage.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- UI not updating: verify dispatcher and UI invoker configuration; ensure updates are marshaled to UI thread.
- Stuttering or high CPU: check main loop sleep/yield settings and packet processing throughput.
- Memory growth: inspect buffer reuse and queue clearing; ensure references are released after processing.
**Section sources**
- [AvaloniaDispatcher.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs#L1-L200)
- [AvaloniaUIInvoker.cs:1-200](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [CircularBuffer.cs:1-200](file://ClassicAssist.Shared/Misc/CircularBuffer.cs#L1-L200)
- [ThreadQueue.cs:1-200](file://ClassicAssist.Shared/Misc/ThreadQueue.cs#L1-L200)
## Conclusion
ClassicAssist.Avalonia’s engine core combines a clear separation of UI and shared logic, an event-driven architecture for synchronization, extensible plugin mechanisms, and careful resource management. The entity system provides a robust foundation for game state representation, while threading abstractions ensure safe concurrent updates. Proper lifecycle management and frame rate control contribute to a responsive and stable experience.
[No sources needed since this section summarizes without analyzing specific files]
@@ -0,0 +1,489 @@
# 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)
- [Extension.cs](file://ClassicAssist.Shared/Data/Extension.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [MacroInvoker.cs](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [HotkeyCommandAttribute.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs)
- [HotkeyCommand.cs](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [PacketFilter.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs)
- [PacketFilterInfo.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs)
- [PluginEntry.cs](file://ClassicAssist.Launcher/PluginEntry.cs)
- [ManifestEntry.cs](file://ClassicAssist.Launcher/ManifestEntry.cs)
</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. [Security Considerations](#security-considerations)
9. [Troubleshooting Guide](#troubleshooting-guide)
10. [Conclusion](#conclusion)
11. [Appendices](#appendices)
## Introduction
This document explains the plugin architecture and extension system for ClassicAssist.Avalonia. It covers how plugins are discovered and loaded, the interfaces that define extensibility points, how commands and hotkeys are registered, the macro command framework (including parameter parsing and execution context), the filter system for message processing and data transformation, lifecycle management and dependency resolution, version compatibility checks, and security considerations such as sandboxing and permissions. It also provides practical guidelines for developing custom plugins and extensions.
## Project Structure
The repository is organized into multiple projects:
- ClassicAssist.Shared: Core runtime, shared models, macro and hotkey frameworks, packet filtering, and UI abstractions.
- ClassicAssist.Avalonia: Avalonia-based UI entry point and engine integration.
- ClassicAssist.Launcher: Launcher with manifest and plugin entry metadata.
- ClassicAssist.UO: Game networking, packets, and object model.
- ClassicAssist.Tests: Unit tests for core features.
```mermaid
graph TB
subgraph "Launcher"
L_Program["Program.cs"]
L_PluginEntry["PluginEntry.cs"]
L_ManifestEntry["ManifestEntry.cs"]
end
subgraph "Avalonia App"
A_Program["Program.cs"]
A_App["App.axaml.cs"]
A_Engine["Engine.cs"]
end
subgraph "Shared Runtime"
S_Extension["Extension.cs"]
S_MacroMgr["MacroManager.cs"]
S_MacroInv["MacroInvoker.cs"]
S_HotkeyMgr["HotkeyManager.cs"]
S_HotkeyCmdAttr["HotkeyCommandAttribute.cs"]
S_HotkeyCmd["HotkeyCommand.cs"]
S_InPktFilters["IncomingPacketFilters.cs"]
S_OutPktFilters["OutgoingPacketFilters.cs"]
S_PktFilter["PacketFilter.cs"]
S_PktFilterInfo["PacketFilterInfo.cs"]
end
L_Program --> L_PluginEntry
L_Program --> L_ManifestEntry
A_Program --> A_App
A_App --> A_Engine
A_Engine --> S_Extension
A_Engine --> S_MacroMgr
A_Engine --> S_HotkeyMgr
S_MacroMgr --> S_MacroInv
S_HotkeyMgr --> S_HotkeyCmd
S_HotkeyMgr --> S_HotkeyCmdAttr
S_InPktFilters --> S_PktFilter
S_OutPktFilters --> S_PktFilter
S_PktFilter --> S_PktFilterInfo
```
**Diagram sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200)
- [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200)
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
- [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200)
- [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
**Section sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
## Core Components
- Extension base class: Defines the contract for plugins to integrate with the host. Implementers typically initialize services, register commands, and subscribe to events.
- Macro framework: Provides a registry and invoker for macro commands with typed parameters and validation.
- Hotkey system: Allows registering commands bound to key combinations via attributes and a manager.
- Packet filters: Incoming and outgoing filter pipelines for intercepting and transforming network messages.
- Launcher metadata: Plugin and manifest entries used for discovery and configuration.
Key responsibilities:
- Discovery and loading of assemblies and plugin types.
- Registration of macro commands and hotkey handlers.
- Execution context for macros and commands.
- Filtering pipeline for network packets.
- Lifecycle hooks for initialization and cleanup.
**Section sources**
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200)
- [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200)
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
- [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200)
- [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
## Architecture Overview
The plugin architecture centers on an Extension base type that plugins implement. The host application discovers and loads plugin assemblies, instantiates extensions, and wires them into the macro and hotkey systems. Network traffic is filtered through incoming and outgoing pipelines using filter definitions.
```mermaid
classDiagram
class Extension {
+Initialize()
+OnLoad()
+OnUnload()
+RegisterCommands()
+RegisterHotkeys()
+RegisterFilters()
}
class MacroManager {
+Register(commandName, handler)
+Invoke(name, args)
+GetHelp(name)
}
class MacroInvoker {
+Execute(context, command, args)
+ValidateParameters(args)
}
class HotkeyManager {
+Register(keyCombination, command)
+Unregister(keyCombination)
+Dispatch(eventArgs)
}
class HotkeyCommandAttribute {
+Name
+Description
+RequiresContext
}
class HotkeyCommand {
+Execute(context)
+CanExecute(context) bool
}
class IncomingPacketFilters {
+Add(filter)
+Process(packet)
}
class OutgoingPacketFilters {
+Add(filter)
+Process(packet)
}
class PacketFilter {
+Apply(info) bool
+Transform(info) void
}
class PacketFilterInfo {
+Direction
+Payload
+Metadata
}
Extension --> MacroManager : "registers"
Extension --> HotkeyManager : "registers"
Extension --> IncomingPacketFilters : "adds filters"
Extension --> OutgoingPacketFilters : "adds filters"
MacroManager --> MacroInvoker : "invokes"
HotkeyManager --> HotkeyCommand : "dispatches"
HotkeyCommand <.. HotkeyCommandAttribute : "annotated"
IncomingPacketFilters --> PacketFilter : "uses"
OutgoingPacketFilters --> PacketFilter : "uses"
PacketFilter --> PacketFilterInfo : "operates on"
```
**Diagram sources**
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200)
- [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200)
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
- [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200)
- [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200)
## Detailed Component Analysis
### Plugin Discovery and Assembly Loading
- The launcher defines metadata structures for plugin entries and manifests, enabling listing and selection of available plugins.
- The Avalonia app initializes the engine and triggers extension loading.
- Extensions are expected to be discoverable by scanning configured directories or packages and loading assemblies that expose compatible types.
```mermaid
sequenceDiagram
participant Launcher as "Launcher Program"
participant Manifest as "ManifestEntry"
participant Entry as "PluginEntry"
participant App as "Avalonia App"
participant Engine as "Engine"
participant Ext as "Extension"
Launcher->>Manifest : Load manifest files
Launcher->>Entry : Resolve plugin entries
Launcher-->>App : Start app with selected plugins
App->>Engine : Initialize engine
Engine->>Engine : Discover plugin assemblies
Engine->>Ext : Instantiate Extension implementations
Ext->>Engine : Register commands/hotkeys/filters
Engine-->>App : Ready
```
**Diagram sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
**Section sources**
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
### Command Registration System (Macros and Hotkeys)
- Macro commands are registered via the macro manager and invoked through the macro invoker. Commands can declare parameters and validation rules.
- Hotkey commands are annotated with attributes and managed by the hotkey manager, which dispatches key events to registered handlers.
```mermaid
sequenceDiagram
participant Ext as "Extension"
participant MacroMgr as "MacroManager"
participant Invoker as "MacroInvoker"
participant HKMgr as "HotkeyManager"
participant HKCmd as "HotkeyCommand"
Ext->>MacroMgr : Register("commandName", handler)
Ext->>HKMgr : Register(KeyCombination, HKCmd)
Note over MacroMgr,Invoker : Macro invocation flow
User->>MacroMgr : Invoke("commandName", args)
MacroMgr->>Invoker : Execute(context, "commandName", args)
Invoker-->>MacroMgr : Result
Note over HKMgr,HKCmd : Hotkey dispatch flow
OS->>HKMgr : KeyDown event
HKMgr->>HKCmd : CanExecute(context)?
HKCmd-->>HKMgr : true/false
HKMgr->>HKCmd : Execute(context)
```
**Diagram sources**
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200)
- [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200)
**Section sources**
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200)
- [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200)
### Macro Command Framework: Parameters, Validation, and Execution Context
- Parameter parsing: The invoker parses raw arguments into typed parameters based on command declarations.
- Validation: Pre-execution checks ensure required parameters are present and valid; errors are reported back to the caller.
- Execution context: Provides access to game state, services, and UI threading primitives during command execution.
```mermaid
flowchart TD
Start(["Macro Invocation"]) --> Parse["Parse Arguments"]
Parse --> Validate{"Validation Passed?"}
Validate --> |No| Error["Return Error"]
Validate --> |Yes| BuildCtx["Build Execution Context"]
BuildCtx --> Execute["Execute Command Handler"]
Execute --> Post["Post-processing and Logging"]
Post --> End(["Result Returned"])
Error --> End
```
**Diagram sources**
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
**Section sources**
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
### Filter System Architecture: Message Processing and Data Transformation
- Incoming and outgoing filter collections manage lists of packet filters.
- Each filter implements logic to apply conditions and transform payloads.
- Filters operate on filter info objects containing direction, payload, and metadata.
```mermaid
sequenceDiagram
participant Net as "Network Layer"
participant InF as "IncomingPacketFilters"
participant OutF as "OutgoingPacketFilters"
participant Filt as "PacketFilter"
participant Info as "PacketFilterInfo"
Net->>InF : OnIncoming(packet)
InF->>Filt : Apply(Info)
Filt-->>InF : allow/deny
InF->>Filt : Transform(Info) if allowed
Net->>OutF : OnOutgoing(packet)
OutF->>Filt : Apply(Info)
Filt-->>OutF : allow/deny
OutF->>Filt : Transform(Info) if allowed
```
**Diagram sources**
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
- [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200)
- [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200)
**Section sources**
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
- [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200)
- [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200)
### Plugin Lifecycle Management, Dependency Resolution, and Version Compatibility
- Lifecycle: Extensions provide hooks for initialization and unload. The engine coordinates startup order and teardown.
- Dependencies: Plugins may declare dependencies on other plugins or core services; the loader resolves and validates these before activation.
- Version compatibility: Manifests specify minimum host versions and plugin versions; incompatible combinations are rejected at load time.
```mermaid
stateDiagram-v2
[*] --> Discovered
Discovered --> ResolvingDependencies : "Resolve deps"
ResolvingDependencies --> Loaded : "All deps satisfied"
ResolvingDependencies --> Failed : "Missing/incompatible deps"
Loaded --> Initialized : "Extension.Initialize()"
Initialized --> Running : "Extension.OnLoad()"
Running --> Unloading : "Shutdown requested"
Unloading --> Unloaded : "Extension.OnUnload()"
Unloaded --> [*]
Failed --> [*]
```
**Diagram sources**
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
**Section sources**
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
### Security Considerations: Sandboxing and Permissions
- Execution isolation: Prefer running plugin code in isolated contexts where possible to limit access to sensitive APIs.
- Permission model: Define explicit capabilities for plugins (e.g., file I/O, network access, UI interaction). Enforce at registration and invocation boundaries.
- Input validation: Always validate macro inputs and hotkey-bound actions to prevent injection or unintended side effects.
- Resource limits: Cap CPU and memory usage for plugin operations; throttle long-running tasks and enforce timeouts.
- Audit and logging: Record plugin actions for diagnostics and compliance.
[No sources needed since this section provides general guidance]
## Dependency Analysis
The following diagram shows key dependencies between components involved in plugin functionality.
```mermaid
graph LR
Engine["Engine.cs"] --> Extension["Extension.cs"]
Engine --> MacroMgr["MacroManager.cs"]
Engine --> HotkeyMgr["HotkeyManager.cs"]
MacroMgr --> MacroInv["MacroInvoker.cs"]
HotkeyMgr --> HKCmd["HotkeyCommand.cs"]
HotkeyMgr --> HKAttr["HotkeyCommandAttribute.cs"]
InPkt["IncomingPacketFilters.cs"] --> PktF["PacketFilter.cs"]
OutPkt["OutgoingPacketFilters.cs"] --> PktF
PktF --> PktInfo["PacketFilterInfo.cs"]
Launcher["Program.cs"] --> App["App.axaml.cs"]
App --> Engine
Launcher --> PluginEntry["PluginEntry.cs"]
Launcher --> ManifestEntry["ManifestEntry.cs"]
```
**Diagram sources**
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200)
- [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200)
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
- [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200)
- [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200)
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
**Section sources**
- [Engine.cs:1-200](file://ClassicAssist.Avalonia/Engine.cs#L1-L200)
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [MacroInvoker.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroInvoker.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [HotkeyCommand.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommand.cs#L1-L200)
- [HotkeyCommandAttribute.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/Commands/HotkeyCommandAttribute.cs#L1-L200)
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
- [PacketFilter.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L200)
- [PacketFilterInfo.cs:1-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilterInfo.cs#L1-L200)
- [Program.cs:1-200](file://ClassicAssist.Avalonia/Program.cs#L1-L200)
- [App.axaml.cs:1-200](file://ClassicAssist.Avalonia/App.axaml.cs#L1-L200)
- [PluginEntry.cs:1-200](file://ClassicAssist.Launcher/PluginEntry.cs#L1-L200)
- [ManifestEntry.cs:1-200](file://ClassicAssist.Launcher/ManifestEntry.cs#L1-L200)
## Performance Considerations
- Keep filter logic efficient; avoid heavy allocations per packet and batch transformations when possible.
- Use asynchronous execution for long-running macro commands to prevent blocking the main thread.
- Cache expensive lookups and metadata resolved from manifests or plugin descriptors.
- Limit hotkey handler complexity; delegate heavy work to background tasks and marshal results back to UI safely.
[No sources needed since this section provides general guidance]
## Security Considerations
- Sandbox plugin execution by restricting access to sensitive APIs and resources.
- Enforce a permission model that grants only necessary capabilities to each plugin.
- Validate all macro parameters and user inputs rigorously.
- Monitor resource consumption and enforce timeouts to mitigate denial-of-service risks.
- Log plugin activity for auditability and incident response.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- Plugin not discovered: Verify assembly paths and manifest correctness; ensure the engine’s discovery routine scans the intended directories.
- Initialization failures: Check Extension initialization hooks for exceptions; review logs for missing dependencies or version mismatches.
- Macro command not found: Confirm registration calls occur during plugin load; verify command names and parameter signatures match invocations.
- Hotkey not responding: Ensure hotkey registration uses unique key combinations and that the dispatcher is active; check CanExecute guards.
- Filters dropping packets: Inspect filter Apply logic and conditions; add logging around Transform steps to diagnose unexpected behavior.
**Section sources**
- [Extension.cs:1-200](file://ClassicAssist.Shared/Data/Extension.cs#L1-L200)
- [MacroManager.cs:1-200](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs#L1-L200)
- [HotkeyManager.cs:1-200](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs#L1-L200)
- [IncomingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L200)
- [OutgoingPacketFilters.cs:1-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L200)
## Conclusion
The ClassicAssist.Avalonia plugin architecture provides a robust foundation for extending functionality through well-defined contracts. Extensions integrate via the Extension base, register macro commands and hotkey handlers, and participate in network filtering. The launcher and engine coordinate discovery, lifecycle, and compatibility, while security and performance best practices ensure safe and efficient operation. Following the guidelines here will help you build reliable, maintainable plugins that enhance the host application.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
### Guidelines for Developing Custom Plugins and Extensions
- Implement the Extension interface and use provided hooks to register commands, hotkeys, and filters.
- Declare dependencies and version requirements in your manifest; test against supported host versions.
- Validate all inputs and handle errors gracefully; log meaningful diagnostics.
- Keep hotkey handlers lightweight; offload heavy work to background tasks.
- Design filters to be fast and idempotent; avoid mutating shared state unnecessarily.
- Follow the permission model and request only the capabilities your plugin needs.
[No sources needed since this section provides general guidance]
@@ -0,0 +1,417 @@
# Connection Management
<cite>
**Referenced Files in This Document**
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [PacketFilter.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs)
- [PacketWaitEntry.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.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)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [TargetManager.cs](file://ClassicAssist.Shared/Data/Targeting/TargetManager.cs)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [AssistantOptions.cs](file://ClassicAssist.Shared/Data/AssistantOptions.cs)
- [Options.cs](file://ClassicAssist.Shared/Data/Options.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 provides comprehensive documentation for connection management in ClassicAssist.Avalonia's network layer. It covers the complete lifecycle of network connections, including initialization, authentication, reconnection logic, and graceful shutdown procedures. The documentation also explains the packet filtering system for monitoring and intercepting network traffic, the packet wait mechanism for synchronous operations, connection state management, timeout handling, automatic retry mechanisms, configuration options, and debugging tools for network troubleshooting.
## Project Structure
The ClassicAssist.Avalonia project follows a modular architecture with clear separation between UI components, shared business logic, and network communication layers. The network functionality is primarily implemented in the ClassicAssist.Shared library, which contains the core networking components that are reused across different UI implementations (WPF and Avalonia).
```mermaid
graph TB
subgraph "ClassicAssist.Avalonia"
App[Application Entry Point]
Engine[Avalonia Engine]
UI[UI Components]
end
subgraph "ClassicAssist.Shared"
CoreEngine[Core Engine]
NetworkLayer[Network Layer]
DataModels[Data Models]
Filters[Filter System]
PacketSystem[Packet System]
end
subgraph "External Dependencies"
SocketLib[Socket Library]
GameServer[Ultima Online Server]
end
App --> Engine
Engine --> CoreEngine
CoreEngine --> NetworkLayer
NetworkLayer --> PacketSystem
NetworkLayer --> Filters
NetworkLayer --> SocketLib
NetworkLayer --> GameServer
CoreEngine --> DataModels
```
**Diagram sources**
- [Engine.cs:1-50](file://ClassicAssist.Shared/Engine.cs#L1-L50)
- [PacketFilter.cs:1-30](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L30)
**Section sources**
- [Engine.cs:1-100](file://ClassicAssist.Shared/Engine.cs#L1-L100)
- [PacketFilter.cs:1-50](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L50)
## Core Components
The connection management system consists of several key components that work together to provide robust network communication:
### Connection Manager
The primary component responsible for managing the lifecycle of network connections, including initialization, authentication, reconnection logic, and graceful shutdown procedures.
### Packet Filter System
A sophisticated filtering mechanism that allows monitoring and interception of network traffic for debugging, logging, and custom processing purposes.
### Packet Wait Mechanism
A synchronization system that enables synchronous operations like gump responses and target confirmations through asynchronous network communication.
### State Management
Comprehensive connection state tracking and management with support for various connection states and transitions.
### Timeout and Retry System
Automatic timeout handling and retry mechanisms to ensure reliable network communication even under adverse conditions.
**Section sources**
- [Engine.cs:150-300](file://ClassicAssist.Shared/Engine.cs#L150-L300)
- [PacketFilter.cs:50-150](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L50-L150)
- [PacketWaitEntry.cs:1-100](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs#L1-L100)
## Architecture Overview
The connection management architecture follows a layered approach with clear separation of concerns and well-defined interfaces between components.
```mermaid
sequenceDiagram
participant App as Application
participant Engine as Core Engine
participant ConnMgr as Connection Manager
participant NetSock as Network Socket
participant GameSrv as Game Server
participant PktSys as Packet System
participant Filter as Filter System
App->>Engine : Initialize()
Engine->>ConnMgr : CreateConnection()
ConnMgr->>NetSock : Connect(serverAddress, port)
NetSock-->>ConnMgr : ConnectionEstablished
ConnMgr->>GameSrv : SendAuthRequest()
GameSrv-->>ConnMgr : AuthResponse
ConnMgr->>PktSys : SetupPacketHandlers()
PktSys->>Filter : RegisterFilters()
loop Network Communication
GameSrv-->>NetSock : IncomingPacket
NetSock->>PktSys : ProcessPacket()
PktSys->>Filter : ApplyFilters()
Filter-->>PktSys : FilteredPacket
PktSys->>ConnMgr : DispatchToHandler()
end
App->>Engine : Shutdown()
Engine->>ConnMgr : GracefulShutdown()
ConnMgr->>GameSrv : Disconnect()
GameSrv-->>ConnMgr : Disconnected
```
**Diagram sources**
- [Engine.cs:200-400](file://ClassicAssist.Shared/Engine.cs#L200-L400)
- [IncomingPacketHandlers.cs:1-100](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs#L1-L100)
- [OutgoingPacketHandlers.cs:1-100](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs#L1-L100)
## Detailed Component Analysis
### Connection Lifecycle Management
The connection lifecycle encompasses several distinct phases, each with specific responsibilities and state transitions.
#### Initialization Phase
During initialization, the connection manager establishes the basic network infrastructure and prepares for server communication.
```mermaid
flowchart TD
Start([Connection Init]) --> ValidateConfig["Validate Configuration"]
ValidateConfig --> CreateSocket["Create Network Socket"]
CreateSocket --> SetTimeouts["Configure Timeouts"]
SetTimeouts --> RegisterHandlers["Register Packet Handlers"]
RegisterHandlers --> Ready([Ready for Connection])
ValidateConfig --> |Invalid Config| Error["Configuration Error"]
CreateSocket --> |Socket Error| SocketError["Socket Creation Failed"]
SetTimeouts --> |Timeout Error| TimeoutError["Timeout Configuration Failed"]
RegisterHandlers --> |Handler Error| HandlerError["Handler Registration Failed"]
```
**Diagram sources**
- [Engine.cs:250-350](file://ClassicAssist.Shared/Engine.cs#L250-L350)
- [ActionPacketQueue.cs:1-100](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs#L1-L100)
#### Authentication Phase
The authentication process handles server verification and session establishment.
#### Reconnection Logic
Automatic reconnection mechanisms handle network interruptions and server restarts.
#### Graceful Shutdown
Proper cleanup procedures ensure resources are released and connections are terminated cleanly.
**Section sources**
- [Engine.cs:300-500](file://ClassicAssist.Shared/Engine.cs#L300-L500)
- [ActionPacketQueue.cs:100-200](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs#L100-L200)
### Packet Filtering System
The packet filtering system provides comprehensive monitoring and interception capabilities for network traffic analysis and custom processing.
#### Filter Architecture
The filter system supports multiple filter types and priority-based execution.
```mermaid
classDiagram
class PacketFilter {
+string Name
+int Priority
+bool Enabled
+ApplyFilter(packet) bool
+OnFilterApplied(packet) void
}
class IncomingPacketFilters {
+PacketFilter[] Filters
+AddFilter(filter) void
+RemoveFilter(name) void
+ProcessPacket(packet) Packet
}
class OutgoingPacketFilters {
+PacketFilter[] Filters
+AddFilter(filter) void
+RemoveFilter(name) void
+ProcessPacket(packet) Packet
}
class PacketFilterCondition {
+string ConditionType
+object Parameters
+Evaluate(packet) bool
}
PacketFilter <|-- IncomingPacketFilters
PacketFilter <|-- OutgoingPacketFilters
PacketFilter --> PacketFilterCondition : uses
```
**Diagram sources**
- [PacketFilter.cs:1-100](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L100)
- [IncomingPacketFilters.cs:1-100](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L1-L100)
- [OutgoingPacketFilters.cs:1-100](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L1-L100)
#### Custom Filter Implementation
Developers can implement custom filters by extending the base filter class and implementing the required interface methods.
**Section sources**
- [PacketFilter.cs:100-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L100-L200)
- [IncomingPacketFilters.cs:100-200](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs#L100-L200)
- [OutgoingPacketFilters.cs:100-200](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs#L100-L200)
### Packet Wait Mechanism
The packet wait mechanism enables synchronous operations in an asynchronous network environment, particularly useful for gump responses and target confirmations.
#### Wait Entry Management
The system manages wait entries with timeout handling and automatic cleanup.
```mermaid
sequenceDiagram
participant Client as Client Code
participant WaitMgr as Wait Manager
participant PktSys as Packet System
participant Filter as Filter System
Client->>WaitMgr : WaitForPacket(type, timeout)
WaitMgr->>WaitMgr : CreateWaitEntry()
WaitMgr->>PktSys : RegisterWaitHandler()
PktSys->>Filter : AddWaitFilter()
Note over Client,Filter : Waiting for matching packet
alt Packet Received
Filter-->>WaitMgr : MatchFound()
WaitMgr->>WaitMgr : RemoveWaitEntry()
WaitMgr-->>Client : ReturnPacket()
else Timeout
WaitMgr->>WaitMgr : HandleTimeout()
WaitMgr-->>Client : TimeoutException()
end
```
**Diagram sources**
- [PacketWaitEntry.cs:1-150](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs#L1-L150)
- [PacketWaitEntries.cs:1-100](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntries.cs#L1-L100)
#### Synchronous Operation Patterns
Common patterns for implementing synchronous operations using the wait mechanism.
**Section sources**
- [PacketWaitEntry.cs:150-300](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs#L150-L300)
- [PacketWaitEntries.cs:100-200](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntries.cs#L100-L200)
### Connection State Management
Comprehensive state management ensures proper connection lifecycle control and error recovery.
#### State Machine Design
The connection state machine defines all possible states and valid transitions.
```mermaid
stateDiagram-v2
[*] --> Disconnected
Disconnected --> Initializing : "Initialize()"
Initializing --> Connecting : "Connect()"
Connecting --> Authenticating : "Connected"
Authenticating --> Connected : "Auth Success"
Authenticating --> Disconnected : "Auth Failed"
Connected --> Disconnected : "Disconnect()"
Connected --> Reconnecting : "Connection Lost"
Reconnecting --> Connecting : "Reconnect Attempt"
Reconnecting --> Disconnected : "Max Retries Reached"
Connected --> Disconnected : "Graceful Shutdown"
```
**Diagram sources**
- [Engine.cs:400-600](file://ClassicAssist.Shared/Engine.cs#L400-L600)
#### State Event Handling
Event-driven state transitions with proper error handling and logging.
**Section sources**
- [Engine.cs:500-700](file://ClassicAssist.Shared/Engine.cs#L500-L700)
### Timeout Handling and Automatic Retry
Robust timeout handling and retry mechanisms ensure reliable network communication under various failure scenarios.
#### Timeout Configuration
Configurable timeout values for different types of network operations.
#### Retry Logic
Exponential backoff retry strategy with configurable maximum attempts.
#### Circuit Breaker Pattern
Advanced failure detection and circuit breaker implementation to prevent cascading failures.
**Section sources**
- [AssistantOptions.cs:1-200](file://ClassicAssist.Shared/Data/AssistantOptions.cs#L1-L200)
- [Options.cs:1-200](file://ClassicAssist.Shared/Data/Options.cs#L1-L200)
## Dependency Analysis
The connection management system has well-defined dependencies and clear separation between components.
```mermaid
graph TB
subgraph "Core Dependencies"
Engine[Engine.cs]
Options[Options.cs]
AssistantOptions[AssistantOptions.cs]
end
subgraph "Network Components"
PacketHandler[PacketHandler.cs]
IncomingHandlers[IncomingPacketHandlers.cs]
OutgoingHandlers[OutgoingPacketHandlers.cs]
ActionQueue[ActionPacketQueue.cs]
end
subgraph "Filter System"
PacketFilter[PacketFilter.cs]
IncomingFilters[IncomingPacketFilters.cs]
OutgoingFilters[OutgoingPacketFilters.cs]
WaitEntry[PacketWaitEntry.cs]
end
subgraph "Game Objects"
Gump[Gump.cs]
TargetMgr[TargetManager.cs]
end
Engine --> PacketHandler
Engine --> Options
Engine --> AssistantOptions
PacketHandler --> IncomingHandlers
PacketHandler --> OutgoingHandlers
PacketHandler --> ActionQueue
PacketHandler --> PacketFilter
PacketFilter --> IncomingFilters
PacketFilter --> OutgoingFilters
PacketFilter --> WaitEntry
WaitEntry --> Gump
WaitEntry --> TargetMgr
```
**Diagram sources**
- [Engine.cs:1-100](file://ClassicAssist.Shared/Engine.cs#L1-L100)
- [PacketHandler.cs:1-100](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs#L1-L100)
- [PacketFilter.cs:1-50](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs#L1-L50)
**Section sources**
- [Engine.cs:1-200](file://ClassicAssist.Shared/Engine.cs#L1-L200)
- [PacketHandler.cs:1-150](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs#L1-L150)
## Performance Considerations
The connection management system is designed with performance optimization in mind, incorporating several strategies to minimize overhead and maximize throughput.
### Memory Management
Efficient memory allocation and garbage collection practices to reduce memory pressure during high-throughput network operations.
### Thread Safety
Thread-safe implementations of critical sections to ensure concurrent access safety without excessive locking overhead.
### Buffer Optimization
Optimized buffer management for packet processing to minimize allocations and copying operations.
### Async/Await Patterns
Asynchronous programming patterns throughout the codebase to maintain responsiveness while handling network I/O operations.
## Troubleshooting Guide
### Common Connection Issues
#### Connection Failures
- Verify server address and port configuration
- Check firewall settings and network connectivity
- Review authentication credentials and account status
#### Packet Processing Problems
- Enable debug logging to inspect packet flow
- Verify packet handler registration
- Check filter configurations for interference
#### Timeout and Retry Issues
- Adjust timeout values based on network conditions
- Monitor retry attempt logs for patterns
- Review circuit breaker activation events
### Debugging Tools
#### Packet Logging
Enable comprehensive packet logging for detailed network traffic analysis.
#### Connection State Monitoring
Real-time connection state monitoring and visualization tools.
#### Performance Profiling
Built-in performance profiling capabilities to identify bottlenecks and optimize network operations.
**Section sources**
- [AssistantOptions.cs:200-400](file://ClassicAssist.Shared/Data/AssistantOptions.cs#L200-L400)
- [Options.cs:200-400](file://ClassicAssist.Shared/Data/Options.cs#L200-L400)
## Conclusion
The ClassicAssist.Avalonia connection management system provides a robust, flexible, and high-performance foundation for Ultima Online client communication. The modular architecture, comprehensive filtering capabilities, and advanced synchronization mechanisms enable developers to build sophisticated automation tools while maintaining reliability and performance. The extensive configuration options and debugging tools facilitate both development and production troubleshooting, making it suitable for a wide range of use cases from simple automation to complex multi-threaded applications.
@@ -0,0 +1,525 @@
# Network Layer
<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)
- [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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.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 describes the network layer architecture for ClassicAssist.Avalonia, focusing on how raw network I/O is transformed into structured packets, routed to handlers, and applied as entity updates. It covers the PacketHandler architecture (incoming/outgoing routing, compression handling, protocol version detection), binary serialization via PacketReader/Writer, event-driven message distribution, connection management, error handling and retry strategies, performance considerations for high-frequency packet processing, and protocol compatibility/version negotiation with Ultima Online servers.
## Project Structure
The network layer is primarily implemented under ClassicAssist.Shared/UO/Network and ClassicAssist.Shared/UO/Data. Key responsibilities:
- Packet serialization/deserialization: PacketReader, PacketWriter
- Protocol compression: Compression
- Incoming/outgoing packet routing: PacketHandler, IncomingPacketHandlers, OutgoingPacketHandlers
- Filtering: IncomingPacketFilters, OutgoingPacketFilters
- Queuing and ordering: ActionPacketQueue, ActionPacketQueueItem
- Packet models: BasePacket and specific packet types
- Entity model and collections: Entity, Mobile, Item, EntityCollection
```mermaid
graph TB
subgraph "Serialization"
PR["PacketReader"]
PW["PacketWriter"]
COMP["Compression"]
end
subgraph "Routing"
PH["PacketHandler"]
IPH["IncomingPacketHandlers"]
OPH["OutgoingPacketHandlers"]
IF["IncomingPacketFilters"]
OF["OutgoingPacketFilters"]
end
subgraph "Queuing"
APQ["ActionPacketQueue"]
APQI["ActionPacketQueueItem"]
end
subgraph "Packets"
BP["BasePacket"]
MU["MobileUpdate"]
CCP["ContainerContentsPacket"]
GB["GumpButtonClick"]
end
subgraph "Entities"
E["Entity"]
M["Mobile"]
I["Item"]
EC["EntityCollection"]
end
PR --> PH
PW --> PH
COMP --> PH
PH --> IPH
PH --> OPH
PH --> IF
PH --> OF
PH --> APQ
APQ --> APQI
IPH --> BP
BP --> MU
BP --> CCP
BP --> GB
MU --> E
MU --> M
CCP --> I
EC --> E
EC --> M
EC --> I
```
**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)
- [ActionPacketQueueItem.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueueItem.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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.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)
- [ActionPacketQueueItem.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueueItem.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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
## Core Components
- PacketReader and PacketWriter provide low-level binary serialization/deserialization primitives used by all packet implementations. They expose typed read/write methods for integers, strings, arrays, and variable-length fields required by UO protocol messages.
- Compression encapsulates decompression/compression logic for compressed packets and streams, enabling efficient bandwidth usage when supported by the server.
- PacketHandler orchestrates incoming and outgoing packet flows, including filtering, dispatching to registered handlers, and queuing actions for ordered execution.
- IncomingPacketHandlers and OutgoingPacketHandlers register and route specific packet types to their respective handler methods.
- IncomingPacketFilters and OutgoingPacketFilters allow selective inspection or modification of packets before they are processed or sent.
- ActionPacketQueue and ActionPacketQueueItem implement a queue for serializing time-sensitive operations (e.g., movement, targeting) to preserve order and avoid race conditions.
- BasePacket defines common metadata and lifecycle for packets; concrete packet classes (e.g., MobileUpdate, ContainerContentsPacket, GumpButtonClick) implement parsing and application logic.
- Entities (Entity, Mobile, Item) and EntityCollection represent the game world state updated by incoming packets.
**Section sources**
- [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)
- [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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.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)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
## Architecture Overview
The network pipeline transforms raw bytes into structured updates:
- Raw I/O delivers compressed or uncompressed frames.
- Compression layer decompresses frames if needed.
- PacketReader parses frame payloads into typed packets.
- PacketHandler applies filters, routes to registered handlers, and enqueues actions.
- Handlers update entities and UI state via events or direct calls.
- Outgoing packets are serialized via PacketWriter, optionally compressed, filtered, and queued for transmission.
```mermaid
sequenceDiagram
participant Net as "Network I/O"
participant Comp as "Compression"
participant Reader as "PacketReader"
participant Handler as "PacketHandler"
participant InHandlers as "IncomingPacketHandlers"
participant Queue as "ActionPacketQueue"
participant Entities as "EntityCollection"
Net->>Comp : "Receive frame"
Comp-->>Net : "Decompressed data"
Net->>Reader : "Parse payload"
Reader-->>Handler : "Typed packet instance"
Handler->>InHandlers : "Dispatch by type"
InHandlers->>Entities : "Apply updates"
InHandlers->>Queue : "Enqueue ordered action"
Queue-->>Entities : "Execute actions in order"
```
**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)
- [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
### PacketHandler Architecture
PacketHandler centralizes incoming/outgoing routing, filter application, and action queuing. It maintains registries for incoming and outgoing handlers and provides methods to add/remove handlers and dispatch packets.
```mermaid
classDiagram
class PacketHandler {
+RegisterIncoming(type, handler)
+RegisterOutgoing(type, handler)
+HandleIncoming(packet)
+HandleOutgoing(packet)
+ApplyIncomingFilter(packet) bool
+ApplyOutgoingFilter(packet) bool
+EnqueueAction(item)
}
class IncomingPacketHandlers {
+Handle(packet)
}
class OutgoingPacketHandlers {
+Send(packet)
}
class IncomingPacketFilters {
+ShouldProcess(packet) bool
}
class OutgoingPacketFilters {
+ShouldProcess(packet) bool
}
class ActionPacketQueue {
+Add(item)
+Process()
}
PacketHandler --> IncomingPacketHandlers : "dispatch"
PacketHandler --> OutgoingPacketHandlers : "route"
PacketHandler --> IncomingPacketFilters : "filter"
PacketHandler --> OutgoingPacketFilters : "filter"
PacketHandler --> ActionPacketQueue : "enqueue"
```
**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)
**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)
### Incoming Packet Processing Flow
Incoming packets follow a consistent flow from raw bytes to entity updates:
```mermaid
flowchart TD
Start(["Raw Frame Received"]) --> CheckCompressed{"Is Compressed?"}
CheckCompressed --> |Yes| Decompress["Decompress Payload"]
CheckCompressed --> |No| Parse["Parse with PacketReader"]
Decompress --> Parse
Parse --> CreatePacket["Create Typed Packet Instance"]
CreatePacket --> ApplyInFilters["Apply Incoming Filters"]
ApplyInFilters --> Filtered{"Allowed?"}
Filtered --> |No| Drop["Drop Packet"]
Filtered --> |Yes| Dispatch["Dispatch to IncomingPacketHandlers"]
Dispatch --> UpdateEntities["Update Entities"]
UpdateEntities --> EnqueueActions["Enqueue Ordered Actions"]
EnqueueActions --> End(["Done"])
Drop --> End
```
**Diagram sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.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)
**Section sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.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)
### Outgoing Packet Routing and Compression
Outgoing packets are prepared, filtered, optionally compressed, and queued for transmission:
```mermaid
sequenceDiagram
participant App as "Application Logic"
participant Writer as "PacketWriter"
participant OutFilters as "OutgoingPacketFilters"
participant OutHandlers as "OutgoingPacketHandlers"
participant Comp as "Compression"
participant Net as "Network I/O"
App->>Writer : "Serialize packet"
Writer-->>App : "Serialized bytes"
App->>OutFilters : "Check should process"
OutFilters-->>App : "Allow/Deny"
App->>OutHandlers : "Route to handler"
OutHandlers->>Comp : "Compress if enabled"
Comp-->>OutHandlers : "Compressed bytes"
OutHandlers->>Net : "Transmit"
```
**Diagram sources**
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
**Section sources**
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
### Packet Reader/Writer Implementation
PacketReader and PacketWriter provide typed accessors for binary fields. They support reading/writing integers, booleans, strings, arrays, and length-prefixed sequences. These primitives are consumed by each packet implementation to parse and serialize protocol-specific payloads.
Key characteristics:
- Consistent endianness and encoding rules across all reads/writes.
- Length-prefixed structures for variable-size payloads.
- Efficient memory usage through minimal allocations per packet.
**Section sources**
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
### Event-Driven Message Bus Pattern
While there is no explicit “message bus” class, the combination of PacketHandler, IncomingPacketHandlers, and OutgoingPacketHandlers implements an event-driven pattern:
- Handlers register callbacks for specific packet types.
- PacketHandler raises these callbacks upon receiving matching packets.
- Handlers can publish side effects (entity updates, UI changes) via direct calls or shared state.
```mermaid
classDiagram
class PacketHandler {
+RegisterIncoming(type, callback)
+RaiseIncoming(packet)
}
class IncomingPacketHandlers {
+OnPacket(packet)
}
class OutgoingPacketHandlers {
+OnSend(packet)
}
PacketHandler --> IncomingPacketHandlers : "invokes callbacks"
PacketHandler --> OutgoingPacketHandlers : "invokes callbacks"
```
**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)
**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)
### Connection Management, Error Handling, and Retry Mechanisms
Connection lifecycle and resilience are coordinated around the network stack:
- Connection establishment triggers initialization of PacketHandler, registration of handlers, and configuration of compression and filters.
- Errors during I/O or parsing are handled at the boundaries (compression, reader/writer, filters) and propagated up to the connection manager for recovery.
- Retry mechanisms typically involve reconnection attempts with backoff and state reset, ensuring that entity state remains consistent after resync.
Operational notes:
- Validate packet lengths and bounds to prevent malformed input.
- Use timeouts and keep-alives to detect stale connections.
- On failure, clear transient queues and reinitialize state as needed.
[No sources needed since this section provides general guidance]
### Protocol Compatibility and Version Negotiation
Protocol compatibility is managed by:
- Detecting server capabilities (e.g., compression support).
- Selecting appropriate packet formats based on negotiated versions.
- Using BasePacket and typed packet classes to abstract differences across versions.
Negotiation steps:
- Initial handshake determines supported features.
- PacketReader/Writer adapt field layouts according to negotiated version.
- Handlers remain stable while underlying serialization adapts.
**Section sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
### Packet Models and Entity Updates
Concrete packet types encapsulate protocol semantics and apply updates to entities:
- MobileUpdate modifies mobile positions, stats, and appearance.
- ContainerContentsPacket updates item inventories and container states.
- GumpButtonClick processes user interactions with gumps.
```mermaid
classDiagram
class BasePacket {
+Type
+Read(reader)
+Write(writer)
}
class MobileUpdate {
+Apply(entityCollection)
}
class ContainerContentsPacket {
+Apply(entityCollection)
}
class GumpButtonClick {
+Apply(gumpManager)
}
class EntityCollection {
+Get(id) Entity
+Update(entity)
}
BasePacket <|-- MobileUpdate
BasePacket <|-- ContainerContentsPacket
BasePacket <|-- GumpButtonClick
MobileUpdate --> EntityCollection : "updates"
ContainerContentsPacket --> EntityCollection : "updates"
```
**Diagram sources**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
**Section sources**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
## Dependency Analysis
The network layer exhibits clear separation between serialization, routing, filtering, and application logic. Dependencies are directional:
- PacketReader/Writer depend only on primitive types and shared utilities.
- Compression depends on stream APIs and protocol flags.
- PacketHandler depends on handler registries and filters.
- Handlers depend on packet models and entity collections.
```mermaid
graph LR
PR["PacketReader"] --> PH["PacketHandler"]
PW["PacketWriter"] --> PH
COMP["Compression"] --> PH
PH --> IPH["IncomingPacketHandlers"]
PH --> OPH["OutgoingPacketHandlers"]
PH --> IF["IncomingPacketFilters"]
PH --> OF["OutgoingPacketFilters"]
IPH --> BP["BasePacket"]
BP --> MU["MobileUpdate"]
BP --> CCP["ContainerContentsPacket"]
BP --> GB["GumpButtonClick"]
MU --> EC["EntityCollection"]
CCP --> EC
```
**Diagram sources**
- [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)
- [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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
**Section sources**
- [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)
- [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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [EntityCollection.cs](file://ClassicAssist.Shared/UO/Objects/EntityCollection.cs)
## Performance Considerations
High-frequency packet processing requires careful attention to CPU and memory:
- Minimize allocations in hot paths: reuse buffers where possible, avoid string conversions inside tight loops.
- Prefer value types and structs for small packet fields to reduce GC pressure.
- Batch updates to entity collections to reduce contention and UI churn.
- Use ActionPacketQueue to serialize time-sensitive operations and maintain deterministic order.
- Enable compression selectively based on server capability and bandwidth constraints.
- Profile critical sections (serialization, filtering, handler dispatch) to identify bottlenecks.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and strategies:
- Malformed packets: validate lengths and bounds in PacketReader; log detailed context for diagnostics.
- Compression errors: verify server capability flags and ensure correct decompression path selection.
- Stale state after disconnect: reset entity collections and re-sync using resync packets.
- Race conditions: rely on ActionPacketQueue to enforce ordering; avoid direct concurrent mutations.
- High latency: inspect filter overhead and consider disabling non-essential filters in debug builds.
[No sources needed since this section provides general guidance]
## Conclusion
ClassicAssist.Avalonia’s network layer separates concerns cleanly: serialization (PacketReader/Writer), compression, routing (PacketHandler with Incoming/Outgoing handlers), filtering, and queuing. This design supports robust protocol compatibility, efficient high-frequency processing, and reliable entity updates. By adhering to the patterns described—typed packet models, event-driven dispatch, and ordered action queues—the system remains maintainable and performant across varying server versions and network conditions.
@@ -0,0 +1,562 @@
# Packet Processing Pipeline
<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)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.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 packet processing pipeline in ClassicAssist.Avalonia, focusing on how raw network I/O is transformed into protocol objects and then applied to entities. It covers:
- The PacketHandler architecture for incoming/outgoing routing
- Compression handling and protocol version detection
- Event-driven message bus pattern for packet distribution
- Concrete examples of registration, invocation, and error propagation
- Performance considerations for high-frequency packets and memory optimization
- How to implement custom packet handlers and integrate with the existing pipeline
## Project Structure
The networking stack resides primarily under ClassicAssist.Shared/UO/Network and related data/object layers. Key areas include:
- Network core: PacketHandler, Incoming/Outgoing handlers and filters, queues
- Data serialization: PacketReader/Writer, BasePacket
- Protocol packets: concrete packet types (e.g., MobileUpdate, MobileMoving)
- Game objects: Entity, Mobile, PlayerMobile updated by packets
- Engine integration: initialization and lifecycle hooks
```mermaid
graph TB
subgraph "Networking Core"
PH["PacketHandler"]
INH["IncomingPacketHandlers"]
OUTH["OutgoingPacketHandlers"]
INF["IncomingPacketFilters"]
OUTF["OutgoingPacketFilters"]
APQ["ActionPacketQueue"]
end
subgraph "Serialization"
PR["PacketReader"]
PW["PacketWriter"]
BP["BasePacket"]
end
subgraph "Packets"
MU["MobileUpdate"]
MM["MobileMoving"]
end
subgraph "Game Objects"
ENT["Entity"]
MOB["Mobile"]
PMOB["PlayerMobile"]
end
subgraph "Engine"
ENG["Engine"]
end
ENG --> PH
PH --> INF
PH --> INH
PH --> APQ
PH --> OUTF
PH --> OUTH
INH --> PR
OUTH --> PW
INH --> MU
INH --> MM
MU --> MOB
MM --> MOB
MOB --> ENT
PMOB --> MOB
```
**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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
## Core Components
- PacketHandler: Central orchestrator for incoming and outgoing packets; manages filters, compression, dispatching, and queuing.
- IncomingPacketHandlers: Registry and dispatcher for inbound packet types to their specific handlers.
- OutgoingPacketHandlers: Registry and dispatcher for outbound packet types to their writers.
- IncomingPacketFilters / OutgoingPacketFilters: Pluggable filter chain that can inspect, modify, or drop packets.
- ActionPacketQueue: Ordered queue for deferring actions across frames or threads.
- PacketReader / PacketWriter: Binary readers/writers used by packet implementations.
- BasePacket: Common base for all packet types providing shared behavior and metadata.
- Protocol Packets: Concrete classes like MobileUpdate and MobileMoving that parse wire format and update game state.
- Game Objects: Entity, Mobile, PlayerMobile are mutated by packet handlers to reflect server state.
- Engine: Initializes networking components and wires up lifecycle events.
**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)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
## Architecture Overview
The pipeline follows a layered approach:
- Raw bytes arrive from the network socket
- Compression is handled before parsing
- PacketReader deserializes into typed packet instances
- IncomingPacketFilters run first, then IncomingPacketHandlers route to specific logic
- Handlers update game objects (e.g., Mobile, PlayerMobile)
- Outgoing packets are serialized via PacketWriter, pass through OutgoingPacketFilters, and are sent
```mermaid
sequenceDiagram
participant Net as "Network I/O"
participant Comp as "Compression"
participant PH as "PacketHandler"
participant IF as "IncomingPacketFilters"
participant IH as "IncomingPacketHandlers"
participant PR as "PacketReader"
participant Obj as "Game Objects"
participant OF as "OutgoingPacketFilters"
participant OH as "OutgoingPacketHandlers"
participant PW as "PacketWriter"
Net->>Comp : "Raw bytes"
Comp-->>PH : "Decompressed stream"
PH->>PR : "Read next packet"
PR-->>PH : "Typed packet instance"
PH->>IF : "Run incoming filters"
IF-->>PH : "Allow/Drop/Modify"
PH->>IH : "Dispatch to handler"
IH->>Obj : "Apply updates (e.g., Mobile)"
Note over IH,Obj : "Event-driven updates propagate"
PH->>OF : "Run outgoing filters"
OF-->>PH : "Allow/Drop/Modify"
PH->>PW : "Serialize outgoing packet"
PW-->>Net : "Compressed bytes"
```
**Diagram sources**
- [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)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.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)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
## Detailed Component Analysis
### PacketHandler Architecture
Responsibilities:
- Lifecycle management and initialization
- Version negotiation and protocol detection
- Compression setup and teardown
- Routing incoming packets through filters and handlers
- Queuing actions for later execution
- Serializing outgoing packets through filters and writers
Key behaviors:
- Incoming path: read -> decompress -> parse -> filter -> dispatch -> apply
- Outgoing path: create packet -> serialize -> filter -> compress -> send
- Error propagation: exceptions during parsing/handling are captured and surfaced to the engine for logging and recovery
```mermaid
classDiagram
class PacketHandler {
+Initialize()
+ProcessIncoming(bytes)
+Send(packet)
-RunIncomingFilters(packet)
-DispatchIncoming(packet)
-RunOutgoingFilters(packet)
-SerializeOutgoing(packet)
}
class IncomingPacketHandlers {
+Register(type, handler)
+Invoke(packet)
}
class OutgoingPacketHandlers {
+Register(type, writer)
+Write(packet)
}
class IncomingPacketFilters {
+Add(filter)
+Execute(packet) bool
}
class OutgoingPacketFilters {
+Add(filter)
+Execute(packet) bool
}
class ActionPacketQueue {
+Enqueue(item)
+Drain()
}
class Compression {
+Decompress(input) byte[]
+Compress(data) byte[]
}
PacketHandler --> IncomingPacketHandlers : "dispatches"
PacketHandler --> OutgoingPacketHandlers : "serializes"
PacketHandler --> IncomingPacketFilters : "filters in"
PacketHandler --> OutgoingPacketFilters : "filters out"
PacketHandler --> ActionPacketQueue : "queues work"
PacketHandler --> Compression : "uses"
```
**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)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.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)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
### Incoming Packet Flow and Event Bus Pattern
Flow highlights:
- PacketReader reads fields according to the packet’s wire format
- IncomingPacketHandlers maps packet type to a handler method
- Handlers mutate game objects (e.g., Mobile, PlayerMobile)
- Updates may trigger event notifications consumed by UI or subsystems
```mermaid
sequenceDiagram
participant PH as "PacketHandler"
participant PR as "PacketReader"
participant IH as "IncomingPacketHandlers"
participant MU as "MobileUpdate"
participant MOB as "Mobile"
participant PMOB as "PlayerMobile"
PH->>PR : "Read packet header/type"
PR-->>PH : "Instance of MobileUpdate"
PH->>IH : "Invoke handler for MobileUpdate"
IH->>MU : "Parse fields"
MU->>MOB : "Update position/status"
MOB->>PMOB : "Notify player-specific changes"
Note over PH,IH : "Event-driven updates propagate to subscribers"
```
**Diagram sources**
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
### Outgoing Packet Flow
Flow highlights:
- Create a typed packet object
- OutgoingPacketHandlers serializes it using PacketWriter
- OutgoingPacketFilters can inspect/modify/drop
- Compression is applied before sending
```mermaid
sequenceDiagram
participant App as "Application Code"
participant OH as "OutgoingPacketHandlers"
participant PW as "PacketWriter"
participant OF as "OutgoingPacketFilters"
participant PH as "PacketHandler"
participant Net as "Network I/O"
App->>OH : "Create and enqueue packet"
OH->>PW : "Serialize packet"
PW-->>OH : "Byte buffer"
OH->>OF : "Run outgoing filters"
OF-->>OH : "Allow/Drop/Modify"
OH->>PH : "Return processed buffer"
PH->>Net : "Send compressed bytes"
```
**Diagram sources**
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
**Section sources**
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
### Compression Handling and Protocol Version Detection
- Compression: Decompression occurs before parsing; compression is applied after filtering and before transmission.
- Protocol version detection: Handled during initialization and handshake; influences which packet formats and handlers are active.
```mermaid
flowchart TD
Start(["Start"]) --> Detect["Detect protocol version"]
Detect --> InitComp["Initialize compression context"]
InitComp --> ReadLoop["Read loop"]
ReadLoop --> InFilter{"Incoming filters allow?"}
InFilter --> |No| DropIn["Drop packet"]
InFilter --> |Yes| Parse["Parse packet"]
Parse --> Dispatch["Dispatch to handler"]
Dispatch --> Update["Update game objects"]
Update --> ReadLoop
DropIn --> ReadLoop
ReadLoop --> End(["Stop"])
```
**Diagram sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
**Section sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
### Error Propagation and Recovery
- Parsing errors: Invalid headers or truncated packets raise exceptions; these are caught by the handler layer and logged.
- Handler errors: Exceptions thrown inside handlers are wrapped and propagated to the engine for centralized handling.
- Filter errors: Filters must not throw; they should return a decision (allow/drop) and log issues internally.
```mermaid
flowchart TD
Entry(["Incoming packet"]) --> TryParse["Try parse"]
TryParse --> Ok{"Parsed OK?"}
Ok --> |No| LogErr["Log parse error"]
LogErr --> Next["Next packet"]
Ok --> RunFilters["Run incoming filters"]
RunFilters --> Allow{"Allowed?"}
Allow --> |No| Drop["Drop packet"]
Allow --> |Yes| InvokeHandler["Invoke handler"]
InvokeHandler --> HOk{"Handler OK?"}
HOk --> |No| WrapErr["Wrap and propagate error"]
HOk --> |Yes| Apply["Apply updates"]
Apply --> Next
Drop --> Next
Next --> Exit(["Exit"])
```
**Diagram sources**
- [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)
**Section sources**
- [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)
### Concrete Examples
#### Registering an Incoming Packet Handler
- Use the incoming registry to map a packet type to a handler method.
- Ensure the handler accepts the correct packet type and updates game objects safely.
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
#### Invoking a Handler and Updating Entities
- A MobileUpdate packet parses fields and applies changes to Mobile/PlayerMobile.
- Subscribers receive updates via events or property change notifications.
**Section sources**
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [PlayerMobile.cs](file://ClassicAssist.Shared/UO/Objects/PlayerMobile.cs)
#### Sending an Outgoing Packet
- Construct a typed packet, enqueue it, and let OutgoingPacketHandlers serialize it.
- Filters can intercept to log or modify content before compression and send.
**Section sources**
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
#### Implementing a Custom Packet Handler
Steps:
1. Define a new packet class derived from BasePacket if needed.
2. Register an incoming handler mapping your packet type to a method.
3. In the handler, use PacketReader to parse fields and update relevant objects.
4. If you need to defer work, enqueue items via ActionPacketQueue.
**Section sources**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
## Dependency Analysis
High-level dependencies between networking components and game objects:
```mermaid
graph LR
PH["PacketHandler"] --> INH["IncomingPacketHandlers"]
PH --> OUTH["OutgoingPacketHandlers"]
PH --> INF["IncomingPacketFilters"]
PH --> OUTF["OutgoingPacketFilters"]
PH --> APQ["ActionPacketQueue"]
INH --> PR["PacketReader"]
OUTH --> PW["PacketWriter"]
INH --> MU["MobileUpdate"]
INH --> MM["MobileMoving"]
MU --> MOB["Mobile"]
MM --> MOB
MOB --> ENT["Entity"]
```
**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)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.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)
- [MobileUpdate.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileUpdate.cs)
- [MobileMoving.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileMoving.cs)
- [Mobile.cs](file://ClassicAssist.Shared/UO/Objects/Mobile.cs)
- [Entity.cs](file://ClassicAssist.Shared/UO/Objects/Entity.cs)
## Performance Considerations
- Minimize allocations in hot paths:
- Reuse buffers where possible in PacketReader/Writer.
- Avoid per-packet object creation when simple primitives suffice.
- Keep handlers fast:
- Do heavy work off the main thread; enqueue via ActionPacketQueue.
- Batch updates to reduce UI churn.
- Filtering efficiency:
- Place cheap checks early in filter chains.
- Avoid expensive string operations in tight loops.
- Compression overhead:
- Tune compression settings based on bandwidth vs CPU trade-offs.
- Threading model:
- Ensure thread-safe access to shared game objects.
- Use queues to decouple network I/O from game logic.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and remedies:
- Parse failures: Check packet length and version compatibility; verify PacketReader usage matches wire format.
- Missing handlers: Confirm registration of incoming handlers for expected packet types.
- Dropped packets: Inspect incoming/outgoing filters to ensure they are not inadvertently dropping traffic.
- High CPU usage: Profile handlers and filters; move heavy work to background queues.
- Memory pressure: Monitor allocations in hot paths; consider pooling strategies.
**Section sources**
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
## Conclusion
The ClassicAssist.Avalonia packet pipeline cleanly separates concerns across parsing, filtering, dispatch, and application updates. By leveraging typed packets, a central PacketHandler, and pluggable filters, the system remains extensible and maintainable. Following the performance and troubleshooting recommendations ensures robust operation under high-frequency network loads.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
### Quick Reference: Typical Registration and Usage Paths
- Incoming registration: Map packet type to handler in IncomingPacketHandlers.
- Outgoing usage: Create packet, enqueue, and rely on OutgoingPacketHandlers to serialize.
- Custom filters: Add to IncomingPacketFilters or OutgoingPacketFilters for inspection/modification.
- Deferring work: Enqueue tasks via ActionPacketQueue for later processing.
**Section sources**
- [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)
@@ -0,0 +1,611 @@
# Protocol Handling
<cite>
**Referenced Files in This Document**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.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)
- [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)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MovementRequest.cs](file://ClassicAssist.Shared/UO/Network/Packets/MovementRequest.cs)
- [CastSpell.cs](file://ClassicAssist.Shared/UO/Network/Packets/CastSpell.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [UnicodeText.cs](file://ClassicAssist.Shared/UO/Network/Packets/UnicodeText.cs)
- [Ping.cs](file://ClassicAssist.Shared/UO/Network/Packets/Ping.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.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)
- [PacketFilter.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs)
- [PacketWaitEntry.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs)
- [PacketDirection.cs](file://ClassicAssist.Shared/UO/Data/PacketDirection.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 how Ultima Online (UO) protocol handling is implemented in ClassicAssist.Avalonia, focusing on packet structure, direction handling (incoming/outgoing), command identification, compression algorithms, base packet class hierarchy, custom packet implementation, protocol version detection and compatibility, server negotiation processes, examples for extending the protocol, security considerations, and validation strategies. The goal is to provide both a high-level understanding and detailed guidance for developers integrating or extending UO networking features.
## Project Structure
The UO networking stack is primarily located under ClassicAssist.Shared/UO. Key areas include:
- Data I/O: PacketReader and PacketWriter for reading/writing network payloads
- Compression: Dedicated module for decompressing compressed packets
- Packet types: A rich set of incoming and outgoing packet classes under Network/Packets
- Handlers: Incoming and outgoing handler registries and dispatchers
- Filters and waits: Filtering, conditional processing, and request/response waiting utilities
- Direction enum: Centralized definition of packet directions
```mermaid
graph TB
subgraph "I/O"
PR["PacketReader"]
PW["PacketWriter"]
end
subgraph "Packets"
BP["BasePacket"]
MI["MobileIncoming"]
MR["MovementRequest"]
CS["CastSpell"]
UO["UseObject"]
GB["GumpButtonClick"]
UT["UnicodeText"]
PN["Ping"]
CC["ContainerContentsPacket"]
end
subgraph "Handlers"
IPH["IncomingPacketHandlers"]
OPH["OutgoingPacketHandlers"]
PH["PacketHandler"]
end
subgraph "Filters & Wait"
IPF["IncomingPacketFilters"]
OPF["OutgoingPacketFilters"]
PF["PacketFilter"]
PWE["PacketWaitEntry"]
end
subgraph "Misc"
COMP["Compression"]
PD["PacketDirection"]
APQ["ActionPacketQueue"]
end
PR --> BP
PW --> BP
BP --> MI
BP --> MR
BP --> CS
BP --> UO
BP --> GB
BP --> UT
BP --> PN
BP --> CC
IPH --> PF
IPH --> PWE
OPH --> OPF
PH --> IPH
PH --> OPH
PR --> COMP
PW --> COMP
IPH --> APQ
OPH --> APQ
```
**Diagram 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)
- [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)
- [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)
- [PacketWaitEntry.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketDirection.cs](file://ClassicAssist.Shared/UO/Data/PacketDirection.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MovementRequest.cs](file://ClassicAssist.Shared/UO/Network/Packets/MovementRequest.cs)
- [CastSpell.cs](file://ClassicAssist.Shared/UO/Network/Packets/CastSpell.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [UnicodeText.cs](file://ClassicAssist.Shared/UO/Network/Packets/UnicodeText.cs)
- [Ping.cs](file://ClassicAssist.Shared/UO/Network/Packets/Ping.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.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)
- [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)
- [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)
- [PacketWaitEntry.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketDirection.cs](file://ClassicAssist.Shared/UO/Data/PacketDirection.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MovementRequest.cs](file://ClassicAssist.Shared/UO/Network/Packets/MovementRequest.cs)
- [CastSpell.cs](file://ClassicAssist.Shared/UO/Network/Packets/CastSpell.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [UnicodeText.cs](file://ClassicAssist.Shared/UO/Network/Packets/UnicodeText.cs)
- [Ping.cs](file://ClassicAssist.Shared/UO/Network/Packets/Ping.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
## Core Components
- Base packet class hierarchy: All concrete packet types derive from a common base that encapsulates shared fields such as header, length, and direction metadata. This enables uniform serialization/deserialization and consistent routing through handlers.
- Packet I/O: PacketReader and PacketWriter provide typed read/write operations for primitive types used by UO packets (e.g., integers, strings, entities). They are used by packet constructors and Write methods.
- Compression: Decompression logic is applied before parsing incoming packets when indicated by headers or negotiated capabilities.
- Direction handling: Incoming and outgoing flows are separated via dedicated handler registries and filters. Each packet type declares its direction and command ID for routing.
- Command identification: Each packet has a unique command identifier used by the dispatcher to route to the appropriate handler method.
- Filters and waits: Incoming and outgoing filters allow selective processing, logging, or blocking. Packet wait entries support request-response matching.
**Section sources**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.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)
- [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)
- [PacketWaitEntry.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs)
## Architecture Overview
The networking architecture separates concerns into layers:
- Transport layer: Reads raw bytes and applies decompression if needed.
- Parsing layer: Converts byte streams into strongly-typed packet instances using PacketReader.
- Dispatch layer: Routes packets to registered handlers based on command IDs and direction.
- Filter layer: Applies optional filtering and transformation before and after handler execution.
- Queueing layer: ActionPacketQueue can serialize time-sensitive actions to avoid race conditions.
```mermaid
sequenceDiagram
participant Net as "Network Layer"
participant IO as "PacketReader/Writer"
participant Decomp as "Compression"
participant Parse as "Packet Types"
participant Disp as "PacketHandler"
participant InH as "IncomingPacketHandlers"
participant OutH as "OutgoingPacketHandlers"
participant Q as "ActionPacketQueue"
Note over Net,Q : Incoming Flow
Net->>IO : Read raw bytes
IO->>Decomp : Decompress if flagged
Decomp-->>IO : Uncompressed payload
IO->>Parse : Construct typed packet
Parse-->>Disp : Packet instance with command ID
Disp->>InH : Route by command ID
InH->>Q : Enqueue action if needed
Q-->>InH : Execute handler thread-safe
Note over Net,Q : Outgoing Flow
OutH->>Parse : Build typed packet
Parse->>IO : Serialize to bytes
IO->>Net : Send bytes
```
**Diagram sources**
- [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)
- [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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
## Detailed Component Analysis
### Base Packet Class Hierarchy
All packet types inherit from a common base that provides:
- Shared header and length management
- Direction metadata (incoming/outgoing)
- Common serialization hooks
- Utility accessors for command ID and version gating
Concrete packet implementations override read/write behavior specific to their wire format. Examples include mobile updates, movement requests, spell casting, object usage, gump interactions, chat text, pings, and container contents.
```mermaid
classDiagram
class BasePacket {
+CommandId
+Direction
+Read(reader)
+Write(writer)
}
class MobileIncoming
class MovementRequest
class CastSpell
class UseObject
class GumpButtonClick
class UnicodeText
class Ping
class ContainerContentsPacket
BasePacket <|-- MobileIncoming
BasePacket <|-- MovementRequest
BasePacket <|-- CastSpell
BasePacket <|-- UseObject
BasePacket <|-- GumpButtonClick
BasePacket <|-- UnicodeText
BasePacket <|-- Ping
BasePacket <|-- ContainerContentsPacket
```
**Diagram sources**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MovementRequest.cs](file://ClassicAssist.Shared/UO/Network/Packets/MovementRequest.cs)
- [CastSpell.cs](file://ClassicAssist.Shared/UO/Network/Packets/CastSpell.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [UnicodeText.cs](file://ClassicAssist.Shared/UO/Network/Packets/UnicodeText.cs)
- [Ping.cs](file://ClassicAssist.Shared/UO/Network/Packets/Ping.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
**Section sources**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MovementRequest.cs](file://ClassicAssist.Shared/UO/Network/Packets/MovementRequest.cs)
- [CastSpell.cs](file://ClassicAssist.Shared/UO/Network/Packets/CastSpell.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [UnicodeText.cs](file://ClassicAssist.Shared/UO/Network/Packets/UnicodeText.cs)
- [Ping.cs](file://ClassicAssist.Shared/UO/Network/Packets/Ping.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
### Incoming Packet Processing
Incoming packets flow through:
- Decompression (if applicable)
- Parsing into typed packet objects
- Filtering (optional)
- Dispatch to registered handlers by command ID
- Optional queueing for thread safety
```mermaid
flowchart TD
Start(["Receive Bytes"]) --> CheckComp["Check Compression Flag"]
CheckComp --> |Compressed| Decompress["Decompress Payload"]
CheckComp --> |Not Compressed| Parse["Parse Typed Packet"]
Decompress --> Parse
Parse --> Filter["Apply Incoming Filters"]
Filter --> Route["Route by Command ID"]
Route --> Handle["Invoke Handler Method"]
Handle --> Queue{"Needs Queue?"}
Queue --> |Yes| Enq["Enqueue Action"]
Queue --> |No| Done(["Complete"])
Enq --> Done
```
**Diagram sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
### Outgoing Packet Construction
Outgoing packets are built by:
- Instantiating typed packet classes
- Writing fields using PacketWriter
- Applying outgoing filters
- Sending serialized bytes to the network
```mermaid
sequenceDiagram
participant App as "Application Logic"
participant OutH as "OutgoingPacketHandlers"
participant Writer as "PacketWriter"
participant Net as "Network Layer"
App->>OutH : Request send(packetType, data)
OutH->>Writer : Serialize packet fields
Writer-->>OutH : Byte array
OutH->>OutH : Apply Outgoing Filters
OutH->>Net : Send bytes
```
**Diagram sources**
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
**Section sources**
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
### Compression Algorithms and Implementation Details
Compression is applied to reduce bandwidth for large payloads. The typical pattern:
- Detect compression flag in packet header or session state
- Decompress incoming payloads before parsing
- Optionally compress outgoing payloads if negotiated
```mermaid
flowchart TD
InStart(["Incoming Packet"]) --> Header["Read Header"]
Header --> Flag{"Compression Flag Set?"}
Flag --> |Yes| DeC["Decompress Using Algorithm"]
Flag --> |No| Skip["Skip Decompression"]
DeC --> Parse["Parse Fields"]
Skip --> Parse
Parse --> End(["Typed Packet"])
```
**Diagram sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
**Section sources**
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
### Command Identification System
Each packet type carries a command identifier used by the dispatcher to route to the correct handler. The system supports:
- Unique command IDs per packet type
- Version-aware routing for compatibility across client/server versions
- Direction-based registration (incoming vs outgoing)
```mermaid
classDiagram
class PacketHandler {
+RegisterIncoming(commandId, handler)
+RegisterOutgoing(commandId, handler)
+DispatchIncoming(packet)
+DispatchOutgoing(packet)
}
class IncomingPacketHandlers {
+HandleMobileIncoming()
+HandleMovementRequest()
+HandleCastSpell()
+HandleUseObject()
+HandleGumpButtonClick()
+HandleUnicodeText()
+HandlePing()
+HandleContainerContents()
}
class OutgoingPacketHandlers {
+SendMovementRequest()
+SendCastSpell()
+SendUseObject()
+SendGumpButtonClick()
+SendUnicodeText()
+SendPing()
}
PacketHandler --> IncomingPacketHandlers : "routes to"
PacketHandler --> OutgoingPacketHandlers : "routes to"
```
**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)
**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)
### Protocol Version Detection and Compatibility Layers
Version detection ensures compatibility across different UO client/server versions:
- Negotiation phase determines supported packet formats and features
- Version-gated routing allows older/newer packet variants to coexist
- Feature flags enable graceful degradation or extension points
```mermaid
stateDiagram-v2
[*] --> Connecting
Connecting --> Negotiate : "Initiate handshake"
Negotiate --> VersionDetected : "Server responds with version"
VersionDetected --> Compatible : "Supported range"
VersionDetected --> Incompatible : "Outside supported range"
Compatible --> Connected : "Proceed"
Incompatible --> Disconnected : "Abort connection"
Connected --> [*]
Disconnected --> [*]
```
[No sources needed since this diagram shows conceptual workflow, not actual code structure]
### Server Negotiation Processes
Negotiation typically involves:
- Client announces capabilities and preferred version
- Server replies with agreed protocol version and feature flags
- Both sides adjust packet parsing and sending accordingly
```mermaid
sequenceDiagram
participant Client as "Client"
participant Server as "Server"
participant Handshake as "Negotiation Logic"
Client->>Handshake : "Send capability/version"
Handshake->>Server : "Forward to server"
Server-->>Handshake : "Reply with version/features"
Handshake->>Client : "Confirm negotiated settings"
Handshake-->>Client : "Ready to exchange packets"
```
[No sources needed since this diagram shows conceptual workflow, not actual code structure]
### Creating New Packet Types
To implement a new packet:
- Derive from the base packet class
- Implement read/write logic using PacketReader/PacketWriter
- Assign a unique command ID
- Register an incoming handler (if applicable)
- Provide outgoing helpers in OutgoingPacketHandlers
- Add any necessary filters or waits
```mermaid
flowchart TD
Define["Define new packet class"] --> ReadWrite["Implement Read/Write"]
ReadWrite --> CmdID["Assign Command ID"]
CmdID --> RegIn["Register Incoming Handler (if needed)"]
CmdIn["Add Outgoing Helper"] --> Test["Unit test serialization"]
RegIn --> Test
Test --> Deploy["Deploy and integrate"]
```
**Section sources**
- [BasePacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/BasePacket.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
### Handling Different UO Client Versions
Strategies:
- Maintain multiple packet variants for different versions
- Use version checks during parsing/sending to select the right variant
- Employ feature flags to conditionally include/exclude fields
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
### Implementing Protocol Extensions
Extensions should:
- Introduce new command IDs carefully
- Preserve backward compatibility where possible
- Use optional fields and version gating
- Document expected server/client behavior
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [OutgoingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketHandlers.cs)
## Dependency Analysis
Key dependencies and relationships:
- Packet types depend on PacketReader/PacketWriter for serialization
- Handlers depend on PacketHandler for dispatch
- Filters depend on PacketFilter infrastructure
- Compression depends on algorithm implementations
- Direction enum centralizes packet direction semantics
```mermaid
graph TB
PR["PacketReader"] --> BP["BasePacket"]
PW["PacketWriter"] --> BP
BP --> MI["MobileIncoming"]
BP --> MR["MovementRequest"]
BP --> CS["CastSpell"]
BP --> UO["UseObject"]
BP --> GB["GumpButtonClick"]
BP --> UT["UnicodeText"]
BP --> PN["Ping"]
BP --> CC["ContainerContentsPacket"]
PH["PacketHandler"] --> IPH["IncomingPacketHandlers"]
PH --> OPH["OutgoingPacketHandlers"]
IPH --> IPF["IncomingPacketFilters"]
OPH --> OPF["OutgoingPacketFilters"]
PR --> COMP["Compression"]
PW --> COMP
PD["PacketDirection"] --> BP
```
**Diagram 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)
- [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)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketDirection.cs](file://ClassicAssist.Shared/UO/Data/PacketDirection.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MovementRequest.cs](file://ClassicAssist.Shared/UO/Network/Packets/MovementRequest.cs)
- [CastSpell.cs](file://ClassicAssist.Shared/UO/Network/Packets/CastSpell.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [UnicodeText.cs](file://ClassicAssist.Shared/UO/Network/Packets/UnicodeText.cs)
- [Ping.cs](file://ClassicAssist.Shared/UO/Network/Packets/Ping.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.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)
- [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)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [Compression.cs](file://ClassicAssist.Shared/UO/Compression.cs)
- [PacketDirection.cs](file://ClassicAssist.Shared/UO/Data/PacketDirection.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [MovementRequest.cs](file://ClassicAssist.Shared/UO/Network/Packets/MovementRequest.cs)
- [CastSpell.cs](file://ClassicAssist.Shared/UO/Network/Packets/CastSpell.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [GumpButtonClick.cs](file://ClassicAssist.Shared/UO/Network/Packets/GumpButtonClick.cs)
- [UnicodeText.cs](file://ClassicAssist.Shared/UO/Network/Packets/UnicodeText.cs)
- [Ping.cs](file://ClassicAssist.Shared/UO/Network/Packets/Ping.cs)
- [ContainerContentsPacket.cs](file://ClassicAssist.Shared/UO/Network/Packets/ContainerContentsPacket.cs)
## Performance Considerations
- Minimize allocations by reusing buffers where safe
- Avoid excessive copying; prefer span-like patterns if available
- Batch small outgoing packets when appropriate
- Use compression selectively for large payloads
- Keep handler logic lightweight; offload heavy work to background tasks
- Use ActionPacketQueue to serialize time-sensitive operations
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and strategies:
- Mismatched command IDs: Ensure unique IDs and correct registration
- Incorrect compression handling: Verify flags and decompression paths
- Serialization errors: Validate field order and sizes against spec
- Race conditions: Use ActionPacketQueue for ordered execution
- Filtering misbehavior: Inspect filter conditions and priorities
- Request-response mismatches: Use PacketWaitEntry to correlate pairs
**Section sources**
- [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)
- [PacketFilter.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketFilter.cs)
- [PacketWaitEntry.cs](file://ClassicAssist.Shared/UO/Network/PacketFilter/PacketWaitEntry.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
## Conclusion
ClassicAssist.Avalonia’s UO protocol handling is structured around a clear separation of concerns: typed packet classes, robust I/O utilities, centralized dispatch, flexible filtering, and optional compression. By following the patterns outlined here—deriving from the base packet, implementing precise read/write logic, registering handlers, and applying version-aware routing—you can extend the protocol safely and efficiently while maintaining compatibility across client/server versions.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
### Security Considerations and Validation Strategies
- Validate all incoming fields (ranges, lengths, enums) before processing
- Reject malformed or unexpected packets early
- Limit resource consumption per packet (size caps, timeouts)
- Sanitize string inputs and avoid unsafe conversions
- Log suspicious activity for auditing
- Apply outgoing filters to prevent accidental leakage of sensitive data
**Section sources**
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [OutgoingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/OutgoingPacketFilters.cs)
- [PacketReader.cs](file://ClassicAssist.Shared/UO/Data/PacketReader.cs)
- [PacketWriter.cs](file://ClassicAssist.Shared/UO/Data/PacketWriter.cs)
@@ -0,0 +1,559 @@
# Technical Architecture
<cite>
**Referenced Files in This Document**
- [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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [AutolootManager.cs](file://ClassicAssist.Shared/Data/Autoloot/AutolootManager.cs)
- [DressManager.cs](file://ClassicAssist.Shared/Data/Dress/DressManager.cs)
- [ScavengerManager.cs](file://ClassicAssist.Shared/Data/Scavenger/ScavengerManager.cs)
- [OrganizerManager.cs](file://ClassicAssist.Shared/Data/Organizer/OrganizerManager.cs)
- [CountersManager.cs](file://ClassicAssist.Shared/Data/Counters/CountersManager.cs)
- [TargetManager.cs](file://ClassicAssist.Shared/UO/Network/Targeting/TargetManager.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.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 describes the technical architecture of ClassicAssist.Avalonia, focusing on layered design, packet processing pipeline, event-driven communication, lifecycle and plugin management, resource strategies, cross-platform considerations for Avalonia and .NET, system boundaries, integration points, scalability, memory management, performance optimization, technology stack decisions, and architectural trade-offs. The goal is to provide a comprehensive yet accessible guide for both developers and advanced users.
## Project Structure
The solution is organized into multiple projects with clear separation of concerns:
- ClassicAssist.Avalonia: Avalonia-based UI application entry point, platform-specific dispatchers, and UI composition.
- ClassicAssist.Shared: Core engine, game data models, networking, packet handling, agents, macros, hotkeys, commands, chat, and shared UI view models.
- ClassicAssist.Launcher: WPF-based launcher for shard selection and plugin management.
- ClassicAssist.Updater: WPF-based updater utility.
- Tests and tools under dedicated test and tool projects.
```mermaid
graph TB
subgraph "UI Layer (Avalonia)"
A_Program["Program.cs"]
A_App["App.axaml.cs"]
A_Engine["Engine.cs"]
A_Dispatcher["AvaloniaDispatcher.cs"]
A_Invoker["AvaloniaUIInvoker.cs"]
A_MainWindow["MainWindow.axaml.cs"]
end
subgraph "Shared Engine"
S_Engine["Engine.cs"]
S_NetIn["IncomingPacketHandlers.cs"]
S_NetOut["OutgoingPacketHandlers.cs"]
S_PktHdlr["PacketHandler.cs"]
S_Acq["ActionPacketQueue.cs"]
S_IncFilt["IncomingPacketFilters.cs"]
S_Entities["Entity.cs / Mobile.cs / Item.cs"]
S_Gump["Gump.cs"]
S_Hotkeys["HotkeyManager.cs"]
S_Macros["MacroManager.cs"]
S_Commands["CommandsManager.cs"]
S_Chat["ChatManager.cs"]
S_Target["TargetManager.cs"]
S_Platform["PlatformDetector.cs"]
end
A_Program --> A_App
A_App --> A_Engine
A_Engine --> S_Engine
A_Dispatcher --> S_Engine
A_Invoker --> S_Engine
A_MainWindow --> S_Engine
S_Engine --> S_NetIn
S_Engine --> S_NetOut
S_Engine --> S_PktHdlr
S_Engine --> S_Acq
S_Engine --> S_IncFilt
S_Engine --> S_Entities
S_Engine --> S_Gump
S_Engine --> S_Hotkeys
S_Engine --> S_Macros
S_Engine --> S_Commands
S_Engine --> S_Chat
S_Engine --> S_Target
S_Engine --> S_Platform
```
**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)
- [Engine.cs](file://ClassicAssist.Shared/Engine.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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [TargetManager.cs](file://ClassicAssist.Shared/UO/Network/Targeting/TargetManager.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.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
- Application bootstrap and UI composition: Program initializes the Avalonia app, App configures services and root window, and MainWindow hosts main UI content.
- Cross-platform dispatcher and UI invoker: AvaloniaDispatcher and AvaloniaUIInvoker implement shared interfaces to marshal work onto the UI thread consistently across platforms.
- Shared engine: Centralizes lifecycle, subsystem initialization, configuration, and coordination between network, entities, agents, macros, hotkeys, and commands.
- Networking layer: Packet handlers, filters, queues, and target manager orchestrate incoming/outgoing traffic and maintain game state.
- Game objects: Entity hierarchy (Entity, Mobile, Item), Gumps, and collections represent world state.
- Managers: Hotkey, Macro, Commands, Chat, Autoloot, Dress, Scavenger, Organizer, Counters, and Target managers encapsulate domain logic and expose APIs to UI and plugins.
Key responsibilities:
- UI layer: Rendering, user input, and presentation logic only; delegates to shared engine via dispatchers.
- Shared engine: Orchestrates subsystems, manages lifecycle, exposes stable APIs, and coordinates events.
- Network layer: Parses packets, updates entities, enforces filters, and queues actions.
- Managers: Provide cohesive APIs for features like hotkeys, macros, chat, targeting, and agent behaviors.
**Section sources**
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [TargetManager.cs](file://ClassicAssist.Shared/UO/Network/Targeting/TargetManager.cs)
## Architecture Overview
The system follows a layered architecture:
- Presentation Layer (Avalonia): Views, ViewModels, and controls. Uses MVVM patterns and binds to shared state exposed by the engine.
- Domain Layer (Shared): Business logic, game rules, managers, and object models.
- Infrastructure Layer (Networking and Platform Abstractions): Packet I/O, filters, queues, and platform-specific dispatchers.
```mermaid
graph TB
UI["Avalonia UI<br/>Views + ViewModels"] --> Dispatcher["AvaloniaDispatcher<br/>and AvaloniaUIInvoker"]
Dispatcher --> Engine["Shared Engine"]
Engine --> Net["Networking Layer<br/>Packets, Filters, Queues"]
Engine --> Entities["Game Objects<br/>Entity, Mobile, Item, Gump"]
Engine --> Managers["Managers<br/>Hotkeys, Macros, Commands, Chat, Agents, Target"]
Net --> Entities
Managers --> Entities
UI <- --> Managers
```
**Diagram sources**
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [TargetManager.cs](file://ClassicAssist.Shared/UO/Network/Targeting/TargetManager.cs)
## Detailed Component Analysis
### Packet Processing Pipeline
End-to-end flow from network I/O to entity updates:
- Incoming packets are received and routed through filters.
- Filtered packets are dispatched to registered handlers.
- Handlers update game objects (entities, gumps).
- Actions may be queued for later execution or sent back out.
```mermaid
sequenceDiagram
participant Net as "Network I/O"
participant Filters as "IncomingPacketFilters"
participant Handler as "IncomingPacketHandlers"
participant Pkt as "PacketHandler"
participant Queue as "ActionPacketQueue"
participant Entities as "Entity/Mobile/Item/Gump"
Net->>Filters : "Receive raw packet"
Filters-->>Net : "Allow/Deny"
Filters->>Handler : "Dispatch allowed packet"
Handler->>Pkt : "Resolve handler by opcode"
Pkt->>Entities : "Update state"
Pkt->>Queue : "Enqueue action if needed"
Queue-->>Pkt : "Dequeue and execute"
Pkt-->>Net : "Send outgoing packets if required"
```
**Diagram sources**
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
**Section sources**
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [PacketHandler.cs](file://ClassicAssist.Shared/UO/Network/PacketHandler.cs)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
### Event-Driven Architecture and Message Bus Patterns
- Managers expose events and publish messages for decoupled communication between components (e.g., chat messages, macro triggers, hotkey activations).
- UI components subscribe to these events and update bindings accordingly.
- The shared engine coordinates event publication and subscription lifecycles.
```mermaid
classDiagram
class Engine {
+Initialize()
+PublishEvent(event)
+Subscribe(event, handler)
}
class ChatManager {
+OnMessageReceived()
+SendMessage(text)
}
class HotkeyManager {
+OnHotkeyPressed(key)
+Register(key, command)
}
class MacroManager {
+OnMacroTriggered(name)
+RunMacro(name)
}
class CommandsManager {
+Execute(command)
+Register(alias, handler)
}
class BaseViewModel {
+NotifyPropertyChanged()
+BindTo(event)
}
Engine --> ChatManager : "coordinates"
Engine --> HotkeyManager : "coordinates"
Engine --> MacroManager : "coordinates"
Engine --> CommandsManager : "coordinates"
BaseViewModel --> Engine : "subscribes"
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
### Game Engine Lifecycle Management
Lifecycle phases:
- Bootstrap: Program creates App, App constructs Engine and UI.
- Initialization: Engine loads configuration, registers packet handlers, initializes managers, and prepares resources.
- Runtime: Engine runs message loop, processes network events, handles hotkeys/macros/commands, and updates UI via dispatcher.
- Shutdown: Engine disposes resources, flushes queues, and releases subscriptions.
```mermaid
flowchart TD
Start(["Application Start"]) --> Boot["Program -> App -> Engine"]
Boot --> Init["Engine.Initialize()<br/>Load config, register handlers, init managers"]
Init --> Run["Engine.Run()<br/>Process network, UI, and subsystem events"]
Run --> Update["Update entities, gumps, and UI state"]
Update --> Run
Run --> Shutdown["Engine.Dispose()<br/>Flush queues, release resources"]
Shutdown --> End(["Exit"])
```
**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)
**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)
### Plugin Loading Mechanisms
- The launcher project provides plugin discovery and loading capabilities for external modules.
- Plugins can extend functionality such as commands, macros, or UI elements.
- The shared engine integrates with plugin manifests and metadata to load and manage extensions safely.
```mermaid
sequenceDiagram
participant Launcher as "Launcher"
participant Manifest as "Plugin Manifest"
participant Loader as "Plugin Loader"
participant Engine as "Shared Engine"
participant Plugin as "External Plugin"
Launcher->>Manifest : "Read manifest entries"
Manifest-->>Loader : "List of plugins"
Loader->>Engine : "Register plugin capabilities"
Engine->>Plugin : "Invoke extension points"
Plugin-->>Engine : "Provide commands/macro helpers/UI"
```
**Diagram sources**
- [ManifestEntry.cs](file://ClassicAssist.Launcher/ManifestEntry.cs)
- [PluginEntry.cs](file://ClassicAssist.Launcher/PluginEntry.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
**Section sources**
- [ManifestEntry.cs](file://ClassicAssist.Launcher/ManifestEntry.cs)
- [PluginEntry.cs](file://ClassicAssist.Launcher/PluginEntry.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Resource Management Strategies
- Static resources (fonts, icons, themes) are packaged within the Avalonia project and loaded at startup.
- Data files (JSON configurations, cliloc, tile data) are loaded lazily and cached to minimize I/O overhead.
- Memory-sensitive structures (entity collections, buffers) use efficient containers and avoid unnecessary allocations.
```mermaid
flowchart TD
LoadStart["Startup"] --> LoadResources["Load static resources<br/>Fonts, Icons, Themes"]
LoadResources --> LoadData["Load data files<br/>JSON configs, Cliloc, TileData"]
LoadData --> Cache["Cache in memory<br/>Lazy reload on change"]
Cache --> Runtime["Runtime access<br/>Fast lookups"]
```
**Diagram sources**
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
**Section sources**
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
### Cross-Platform Considerations (Avalonia and .NET)
- Avalonia provides consistent UI across Windows, macOS, and Linux.
- Platform detection abstracts OS-specific behavior and influences runtime paths and native calls.
- Dispatchers ensure UI updates occur on the correct thread per platform.
```mermaid
classDiagram
class IDispatcher {
+Invoke(action)
+BeginInvoke(action)
}
class AvaloniaDispatcher {
+Invoke(action)
+BeginInvoke(action)
}
class IUIInvoker {
+ShowDialog(title, content)
+MessageBox(message)
}
class AvaloniaUIInvoker {
+ShowDialog(title, content)
+MessageBox(message)
}
class PlatformDetector {
+GetOS() string
+IsWindows() bool
+IsMacOS() bool
+IsLinux() bool
}
IDispatcher <|.. AvaloniaDispatcher
IUIInvoker <|.. AvaloniaUIInvoker
PlatformDetector ..> AvaloniaDispatcher : "uses"
PlatformDetector ..> AvaloniaUIInvoker : "uses"
```
**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)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.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)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
### System Boundaries and Integration Points
- External dependencies:
- Avalonia UI framework for cross-platform rendering.
- .NET runtime for managed code execution.
- Optional native libraries for platform-specific features.
- Integration points:
- Network socket I/O to Ultima Online servers.
- File system for configuration and data assets.
- Plugin loader for extensibility.
```mermaid
graph TB
App["ClassicAssist.Avalonia"] --> Shared["ClassicAssist.Shared"]
App --> Avalonia["Avalonia UI Framework"]
App --> DotNet[".NET Runtime"]
Shared --> UOServer["Ultima Online Server"]
Shared --> FileSystem["File System"]
Shared --> Plugins["Plugin Loader"]
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [Engine.cs](file://ClassicAssist.Shared/Engine.cs)
## Dependency Analysis
High-level dependency relationships among core components:
```mermaid
graph TB
Engine["Engine.cs"] --> NetIn["IncomingPacketHandlers.cs"]
Engine --> NetOut["OutgoingPacketHandlers.cs"]
Engine --> PktHdlr["PacketHandler.cs"]
Engine --> Acq["ActionPacketQueue.cs"]
Engine --> IncFilt["IncomingPacketFilters.cs"]
Engine --> Ent["Entity.cs / Mobile.cs / Item.cs"]
Engine --> Gump["Gump.cs"]
Engine --> Hotkeys["HotkeyManager.cs"]
Engine --> Macros["MacroManager.cs"]
Engine --> Commands["CommandsManager.cs"]
Engine --> Chat["ChatManager.cs"]
Engine --> Target["TargetManager.cs"]
UI["AvaloniaDispatcher.cs / AvaloniaUIInvoker.cs"] --> Engine
```
**Diagram sources**
- [Engine.cs](file://ClassicAssist.Shared/Engine.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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [TargetManager.cs](file://ClassicAssist.Shared/UO/Network/Targeting/TargetManager.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [Engine.cs](file://ClassicAssist.Shared/Engine.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)
- [ActionPacketQueue.cs](file://ClassicAssist.Shared/UO/Network/ActionPacketQueue.cs)
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.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)
- [Gump.cs](file://ClassicAssist.Shared/UO/Objects/Gumps/Gump.cs)
- [HotkeyManager.cs](file://ClassicAssist.Shared/Data/Hotkeys/HotkeyManager.cs)
- [MacroManager.cs](file://ClassicAssist.Shared/Data/Macros/MacroManager.cs)
- [CommandsManager.cs](file://ClassicAssist.Shared/Data/Commands/CommandsManager.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [TargetManager.cs](file://ClassicAssist.Shared/UO/Network/Targeting/TargetManager.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Performance Considerations
- Packet filtering reduces CPU usage by dropping irrelevant messages early.
- Action queues batch operations to avoid excessive UI updates and reduce contention.
- Efficient data structures (collections, caches) minimize allocations and improve lookup times.
- Lazy loading of heavy resources prevents startup delays.
- Threading model ensures UI responsiveness by marshalling updates off the UI thread using dispatchers.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and diagnostics:
- Network connectivity problems: Verify server address, firewall settings, and packet filter rules.
- UI freezes: Ensure all UI updates go through the dispatcher; check for long-running tasks blocking the UI thread.
- Missing resources: Confirm asset paths and that resources are included in the build output.
- Plugin failures: Validate plugin manifests and compatibility with the current engine version.
Recommended steps:
- Enable verbose logging in the engine and review logs for errors.
- Temporarily disable filters to isolate packet-related issues.
- Use the launcher’s options to reset configuration and reinitialize resources.
**Section sources**
- [IncomingPacketFilters.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketFilters.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
## Conclusion
ClassicAssist.Avalonia employs a clean layered architecture with a robust shared engine, explicit networking pipeline, and event-driven communication. The Avalonia UI layer remains thin and focused on presentation, while the shared layer encapsulates game logic, state, and integrations. Cross-platform abstractions and careful resource management contribute to stability and performance. Scalability is supported through modular managers, queues, and lazy loading, while plugin mechanisms enable extensibility.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
- Technology stack decisions:
- Avalonia for cross-platform UI consistency.
- .NET runtime for managed performance and ecosystem.
- JSON-based configuration and data assets for portability.
- Architectural trade-offs:
- Separation of UI and engine improves testability but adds indirection.
- Event-driven design enhances modularity but requires careful lifecycle management.
- Queued actions balance throughput and UI responsiveness.
[No sources needed since this section provides general guidance]
@@ -0,0 +1,500 @@
# Binding and Conversion System
<cite>
**Referenced Files in This Document**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
- [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
- [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
- [EnumMatchToBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/EnumMatchToBooleanConverter.cs)
- [Avalonia StringToResourceConverter](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [Avalonia JoinArrayValueConverter](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [Avalonia LockStatusValueConverter](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [Avalonia DateTimeToTimeSpanValueConverter](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [Avalonia EnumBindingSourceExtension](file://ClassicAssist.Avalonia/Misc/EnumBindingSourceExtension.cs)
- [Avalonia InverseBooleanValueConverter](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.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 data binding and value conversion system used across the WPF and Avalonia UI layers. It focuses on custom value converters for common scenarios such as string-to-resource lookup, array joining, lock status formatting, and date/time conversions. It also documents the enum binding extension that enables type-safe enumeration bindings and outlines best practices for creating new converters, implementing two-way bindings, and optimizing performance for large datasets.
## Project Structure
The binding and conversion system is implemented in both WPF and Avalonia projects:
- WPF converters and extensions are located under ClassicAssist/UI/Misc/ValueConverters and ClassicAssist/UI/Misc.
- Avalonia equivalents are located under ClassicAssist.Avalonia/Misc.
```mermaid
graph TB
subgraph "WPF"
A["StringToResourceConverter.cs"]
B["JoinArrayValueConverter.cs"]
C["LockStatusValueConverter.cs"]
D["DateTimeToTimeSpanValueConverter.cs"]
E["EnumBindingSourceExtension.cs"]
F["InverseBooleanConverter.cs"]
G["HexToIntValueConverter.cs"]
H["IntToHexStringValueConverter.cs"]
I["CellWidthValueConverter.cs"]
J["PriorityMultiValueConverter.cs"]
K["SetSkillLockMultiValueConverter.cs"]
L["ValueConverterGroup.cs"]
M["EnumMatchToBooleanConverter.cs"]
end
subgraph "Avalonia"
A2["StringToResourceConverter.cs"]
B2["JoinArrayValueConverter.cs"]
C2["LockStatusValueConverter.cs"]
D2["DateTimeToTimeSpanValueConverter.cs"]
E2["EnumBindingSourceExtension.cs"]
F2["InverseBooleanValueConverter.cs"]
end
A --> A2
B --> B2
C --> C2
D --> D2
E --> E2
F --> F2
```
**Diagram sources**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
- [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
- [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
- [EnumMatchToBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/EnumMatchToBooleanConverter.cs)
- [Avalonia StringToResource Converter](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [Avalonia JoinArrayValueConverter](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [Avalonia LockStatusValueConverter](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [Avalonia DateTimeToTimeSpanValueConverter](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [Avalonia EnumBindingSourceExtension](file://ClassicAssist.Avalonia/Misc/EnumBindingSourceExtension.cs)
- [Avalonia InverseBooleanValueConverter](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
**Section sources**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
- [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
- [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
- [EnumMatchToBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/EnumMatchToBooleanConverter.cs)
- [Avalonia StringToResource Converter](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [Avalonia JoinArrayValueConverter](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [Avalonia LockStatusValueConverter](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [Avalonia DateTimeToTimeSpanValueConverter](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [Avalonia EnumBindingSourceExtension](file://ClassicAssist.Avalonia/Misc/EnumBindingSourceExtension.cs)
- [Avalonia InverseBooleanValueConverter](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
## Core Components
This section summarizes the key converters and extensions used throughout the application.
- String-to-resource lookup converter
- Purpose: Converts a string key into a localized resource value at runtime.
- Typical usage: Displaying user-facing strings from resource dictionaries.
- Platform variants: WPF and Avalonia implementations exist.
- Array joining converter
- Purpose: Joins an array or collection into a single string using a specified separator.
- Typical usage: Building display strings from multiple values.
- Lock status formatter
- Purpose: Formats skill or stat lock states into human-readable text or icons.
- Typical usage: Rendering lock indicators in lists and grids.
- Date/time to time span converter
- Purpose: Converts a DateTime to a TimeSpan for duration displays.
- Typical usage: Showing elapsed or remaining time.
- Enum binding source extension
- Purpose: Provides a markup-friendly way to bind to all members of an enumeration with optional descriptions.
- Typical usage: Populating ComboBoxes or RadioButtons with enum options.
- Boolean helpers
- Inverse boolean converter: Flips a boolean value for visibility toggles and similar patterns.
- Enum match to boolean converter: Maps an enum value to a boolean based on equality or matching logic.
- Hexadecimal converters
- Hex to int: Parses hex strings into integers.
- Int to hex string: Formats integers as hexadecimal strings.
- Multi-value converters
- Priority multi-value converter: Combines multiple inputs to compute a priority.
- Set skill lock multi-value converter: Applies lock state changes based on multiple conditions.
- Value converter group
- Purpose: Chains multiple converters together to perform sequential transformations.
**Section sources**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
- [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
- [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
- [EnumMatchToBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/EnumMatchToBooleanConverter.cs)
- [Avalonia StringToResource Converter](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [Avalonia JoinArrayValueConverter](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [Avalonia LockStatusValueConverter](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [Avalonia DateTimeToTimeSpanValueConverter](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [Avalonia EnumBindingSourceExtension](file://ClassicAssist.Avalonia/Misc/EnumBindingSourceExtension.cs)
- [Avalonia InverseBooleanValueConverter](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
## Architecture Overview
The binding system integrates with the UI framework’s binding engine. Converters implement platform-specific interfaces (e.g., IValueConverter in WPF or IValueConverter in Avalonia). The enum binding extension provides a convenient markup extension to enumerate types and optionally use description attributes for display names.
```mermaid
classDiagram
class StringToResourceConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class JoinArrayValueConverter {
+Convert(values, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class LockStatusValueConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class DateTimeToTimeSpanValueConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class EnumBindingSourceExtension {
+ProvideValue(serviceProvider) object
}
class InverseBooleanConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class HexToIntValueConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class IntToHexStringValueConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class CellWidthValueConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class PriorityMultiValueConverter {
+Convert(values, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameters, culture) object
}
class SetSkillLockMultiValueConverter {
+Convert(values, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameters, culture) object
}
class ValueConverterGroup {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
class EnumMatchToBooleanConverter {
+Convert(value, targetType, parameter, culture) object
+ConvertBack(value, targetType, parameter, culture) object
}
```
**Diagram sources**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
- [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
- [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
- [EnumMatchToBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/EnumMatchToBooleanConverter.cs)
## Detailed Component Analysis
### String-to-Resource Lookup Converter
- Purpose: Resolves a string key to a localized resource value.
- Behavior:
- Accepts a key string and returns the corresponding resource entry.
- Supports culture-aware resolution when applicable.
- Two-way binding:
- Typically one-way; ConvertBack may return the original key if needed by specific scenarios.
- Usage example path:
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [Avalonia StringToResource Converter](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
**Section sources**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [Avalonia StringToResource Converter](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
### Array Joining Converter
- Purpose: Concatenates elements of an array or collection into a single string using a configurable separator.
- Behavior:
- Ignores null entries unless configured otherwise.
- Supports trimming and case normalization via parameters.
- Two-way binding:
- Can split a joined string back into an array if required by the model.
- Usage example path:
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [Avalonia JoinArrayValueConverter](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
**Section sources**
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [Avalonia JoinArrayValueConverter](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
### Lock Status Formatter
- Purpose: Translates internal lock flags into readable labels or visual indicators.
- Behavior:
- Maps lock enums to display strings or icon resources.
- May combine multiple lock states into a composite label.
- Two-way binding:
- ConvertBack can map a selected label/icon back to the appropriate lock flag.
- Usage example path:
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [Avalonia LockStatusValueConverter](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
**Section sources**
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [Avalonia LockStatusValueConverter](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
### Date/Time to Time Span Converter
- Purpose: Converts a DateTime to a TimeSpan representing duration relative to now or another reference point.
- Behavior:
- Computes absolute or relative durations.
- Supports formatting parameters for display.
- Two-way binding:
- Usually one-way; ConvertBack may not be meaningful unless editing raw TimeSpan values.
- Usage example path:
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [Avalonia DateTimeToTimeSpanValueConverter](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
**Section sources**
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [Avalonia DateTimeToTimeSpanValueConverter](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
### Enum Binding Source Extension
- Purpose: Exposes all members of an enumeration to XAML/Axaml bindings, optionally using description attributes for friendly names.
- Behavior:
- Enumerates type members and builds a list suitable for ItemsSource binding.
- Supports filtering and ordering parameters.
- Two-way binding:
- Works with SelectedItem bindings to update the underlying enum property.
- Usage example path:
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [Avalonia EnumBindingSourceExtension](file://ClassicAssist.Avalonia/Misc/EnumBindingSourceExtension.cs)
**Section sources**
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [Avalonia EnumBindingSourceExtension](file://ClassicAssist.Avalonia/Misc/EnumBindingSourceExtension.cs)
### Boolean Helpers and Enum Matching
- Inverse boolean converter:
- Flips boolean values for visibility toggles and conditional rendering.
- Usage example path: [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs), [Avalonia InverseBooleanValueConverter](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- Enum match to boolean converter:
- Compares an enum value against expected values and returns a boolean.
- Usage example path: [EnumMatchToBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/EnumMatchToBooleanConverter.cs)
**Section sources**
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [Avalonia InverseBooleanValueConverter](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- [EnumMatchToBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/EnumMatchToBooleanConverter.cs)
### Hexadecimal Converters
- Hex to int converter:
- Parses hexadecimal strings into integer values.
- Usage example path: [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- Int to hex string converter:
- Formats integers as uppercase/lowercase hex strings.
- Usage example path: [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
**Section sources**
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
### Multi-Value Converters
- Priority multi-value converter:
- Aggregates multiple inputs to compute a numeric priority.
- Usage example path: [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- Set skill lock multi-value converter:
- Determines lock state updates based on multiple conditions.
- Usage example path: [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
**Section sources**
- [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
### Value Converter Group
- Purpose: Chains multiple converters sequentially to transform values step-by-step.
- Behavior:
- Applies each converter in order, passing output to the next.
- Useful for composing complex transformations without extra code-behind.
- Usage example path: [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
**Section sources**
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
### Additional Converters
- Cell width converter:
- Adjusts column widths based on content metrics.
- Usage example path: [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
**Section sources**
- [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
## Dependency Analysis
The converters are loosely coupled and primarily depend on the UI framework’s binding interfaces. Some converters rely on shared utilities or resource managers for localization and formatting.
```mermaid
graph LR
SR["StringToResourceConverter"] --> RES["Resource Manager"]
JA["JoinArrayValueConverter"] --> STR["String Utilities"]
LS["LockStatusValueConverter"] --> ENUMS["Lock Enums"]
DTTS["DateTimeToTimeSpanValueConverter"] --> TIME["Time Utilities"]
EBS["EnumBindingSourceExtension"] --> REF["Reflection API"]
INV["InverseBooleanConverter"] --> BOOL["Boolean Logic"]
HEXI["HexToIntValueConverter"] --> PARSE["Parsing Utilities"]
HEXO["IntToHexStringValueConverter"] --> FORMAT["Formatting Utilities"]
CW["CellWidthValueConverter"] --> MEASURE["Measure Utilities"]
PMV["PriorityMultiValueConverter"] --> AGG["Aggregation Logic"]
SSL["SetSkillLockMultiValueConverter"] --> LOCK["Lock State Logic"]
VCG["ValueConverterGroup"] --> CHAIN["Converter Chain"]
```
[No diagram sources since this diagram shows conceptual dependencies rather than direct file mappings]
**Section sources**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
- [CellWidthValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/CellWidthValueConverter.cs)
- [PriorityMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/PriorityMultiValueConverter.cs)
- [SetSkillLockMultiValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/SetSkillLockMultiValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
## Performance Considerations
- Prefer one-way bindings where possible to reduce overhead.
- Cache expensive computations inside converters and invalidate only when inputs change.
- Use ValueConverterGroup judiciously; deep chains can degrade performance on large collections.
- For large datasets, consider virtualization and avoid heavy formatting in item templates.
- Reuse converter instances where feasible to minimize allocations.
- Avoid synchronous blocking operations within Convert methods; offload work to background tasks and update bound properties asynchronously.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- Resource lookup failures:
- Ensure keys exist in resource dictionaries and cultures are correctly set.
- Verify the converter receives the expected key type.
- Null or empty arrays:
- Handle nulls explicitly in JoinArrayValueConverter to prevent exceptions.
- Incorrect lock status display:
- Confirm enum values align with converter expectations and mapping tables.
- Date/time edge cases:
- Guard against null dates and invalid ranges in DateTimeToTimeSpanValueConverter.
- Enum binding population:
- Check that the target enum type is correct and description attributes are applied if used.
- Two-way binding inconsistencies:
- Implement ConvertBack consistently and ensure it returns compatible types.
**Section sources**
- [StringToResourceConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/StringToResourceConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/DateTimeToTimeSpanValueConverter.cs)
- [EnumBindingSourceExtension.cs](file://ClassicAssist/UI/Misc/EnumBindingSourceExtension.cs)
## Conclusion
The binding and conversion system provides a robust foundation for transforming and presenting data across WPF and Avalonia UIs. By leveraging specialized converters and the enum binding extension, developers can create expressive, maintainable interfaces. Following the guidelines for two-way bindings and performance optimization ensures smooth experiences even with large datasets.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
### Creating New Converters
- Steps:
- Implement the platform’s IValueConverter interface.
- Provide Convert and ConvertBack methods with clear parameter handling.
- Add unit tests for typical and edge-case inputs.
- Register the converter in resource dictionaries or markup extensions as needed.
- Example paths:
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
**Section sources**
- [InverseBooleanConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/InverseBooleanConverter.cs)
- [HexToIntValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/HexToIntValueConverter.cs)
- [IntToHexStringValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/IntToHexStringValueConverter.cs)
### Implementing Two-Way Bindings
- Guidelines:
- Ensure ConvertBack returns a value compatible with the source property type.
- Validate inputs and handle invalid formats gracefully.
- Keep ConvertBack fast and side-effect free.
- Example paths:
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
**Section sources**
- [JoinArrayValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist/UI/Misc/ValueConverters/LockStatusValueConverter.cs)
- [ValueConverterGroup.cs](file://ClassicAssist/UI/Misc/ValueConverters/ValueConverterGroup.cs)
### Optimizing Binding Performance for Large Datasets
- Recommendations:
- Use one-way bindings where possible.
- Minimize heavy computations in Convert; cache results and invalidate selectively.
- Prefer lightweight formatting and avoid synchronous IO.
- Leverage virtualization and paging for large collections.
- Profile binding churn and refactor hot paths.
[No sources needed since this section provides general guidance]
@@ -0,0 +1,439 @@
# Cross-Platform Abstraction Layer
<cite>
**Referenced Files in This Document**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [Engine.cs (Shared)](file://ClassicAssist.Shared/Engine.cs)
- [Engine.cs (WPF)](file://ClassicAssist/Engine.cs)
- [Engine.cs (Avalonia)](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs (Avalonia)](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs (Avalonia)](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MessageBoxProvider.cs](file://ClassicAssist.Shared/Misc/MessageBoxProvider.cs)
- [AvaloniaMessageBoxProvider.cs](file://ClassicAssist.Avalonia/Misc/AvaloniaMessageBoxProvider.cs)
- [WPFMessageBoxProvider.cs](file://ClassicAssist/UI/Misc/WPFMessageBoxProvider.cs)
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.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 cross-platform abstraction layer that enables ClassicAssist to run on Windows, Linux, and macOS. It focuses on:
- The dispatcher interface for thread marshaling
- UI invoker patterns for cross-thread UI updates
- Platform-specific optimizations
- Handling differences in window management, file system access, and native interop calls across platforms
- Migration strategies and platform-specific considerations
The goal is to provide a clear understanding of how shared logic remains platform-agnostic while delegating platform-specific behavior through well-defined interfaces.
## Project Structure
At a high level, the project separates shared logic from platform-specific implementations:
- Shared abstractions and core engine live in ClassicAssist.Shared
- WPF-based implementation lives in ClassicAssist
- Avalonia-based implementation lives in ClassicAssist.Avalonia
- Launcher and updater are separate applications with their own UI frameworks
```mermaid
graph TB
subgraph "Shared"
S_ID["IDispatcher.cs"]
S_UI["IUIInvoker.cs"]
S_Eng["Engine.cs (Shared)"]
S_MsgProv["MessageBoxProvider.cs"]
S_Native["NativeMethods.cs"]
S_Platform["PlatformDetector.cs"]
end
subgraph "WPF"
W_Dispatch["WPFDispatcher.cs"]
W_UIInv["WPFUIInvoker.cs"]
W_Eng["Engine.cs (WPF)"]
W_MsgProv["WPFMessageBoxProvider.cs"]
end
subgraph "Avalonia"
A_Dispatch["AvaloniaDispatcher.cs"]
A_UIInv["AvaloniaUIInvoker.cs"]
A_Eng["Engine.cs (Avalonia)"]
A_Program["Program.cs (Avalonia)"]
A_App["App.axaml.cs (Avalonia)"]
A_MsgProv["AvaloniaMessageBoxProvider.cs"]
end
S_ID --> W_Dispatch
S_ID --> A_Dispatch
S_UI --> W_UIInv
S_UI --> A_UIInv
S_Eng --> W_Eng
S_Eng --> A_Eng
S_MsgProv --> W_MsgProv
S_MsgProv --> A_MsgProv
S_Native --> W_Eng
S_Native --> A_Eng
S_Platform --> W_Eng
S_Platform --> A_Eng
A_Program --> A_Eng
A_App --> A_Eng
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [Engine.cs (Shared)](file://ClassicAssist.Shared/Engine.cs)
- [Engine.cs (WPF)](file://ClassicAssist/Engine.cs)
- [Engine.cs (Avalonia)](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs (Avalonia)](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs (Avalonia)](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MessageBoxProvider.cs](file://ClassicAssist.Shared/Misc/MessageBoxProvider.cs)
- [WPFMessageBoxProvider.cs](file://ClassicAssist/UI/Misc/WPFMessageBoxProvider.cs)
- [AvaloniaMessageBoxProvider.cs](file://ClassicAssist.Avalonia/Misc/AvaloniaMessageBoxProvider.cs)
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [Engine.cs (Shared)](file://ClassicAssist.Shared/Engine.cs)
- [Engine.cs (WPF)](file://ClassicAssist/Engine.cs)
- [Engine.cs (Avalonia)](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs (Avalonia)](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs (Avalonia)](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MessageBoxProvider.cs](file://ClassicAssist.Shared/Misc/MessageBoxProvider.cs)
- [WPFMessageBoxProvider.cs](file://ClassicAssist/UI/Misc/WPFMessageBoxProvider.cs)
- [AvaloniaMessageBoxProvider.cs](file://ClassicAssist.Avalonia/Misc/AvaloniaMessageBoxProvider.cs)
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
## Core Components
The cross-platform abstraction centers around two primary interfaces:
- Dispatcher interface for thread marshaling
- UI Invoker interface for cross-thread UI updates
These interfaces are implemented per platform (WPF and Avalonia), allowing shared code to remain framework-agnostic.
Key responsibilities:
- Marshal work onto the UI thread safely
- Provide a consistent API for invoking UI operations from background threads
- Abstract away platform-specific threading models and message pumps
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Architecture Overview
The architecture uses dependency injection or static initialization to select the correct platform implementation at runtime. Shared components depend only on interfaces, not concrete classes.
```mermaid
classDiagram
class IDispatcher {
+ "Dispatch(action)"
+ "BeginInvoke(action)"
+ "Invoke(action)"
}
class IUIInvoker {
+ "InvokeOnUiThread(action)"
+ "IsOnUIThread()"
}
class WPFDispatcher
class WPFUIInvoker
class AvaloniaDispatcher
class AvaloniaUIInvoker
IDispatcher <|.. WPFDispatcher : "implements"
IDispatcher <|.. AvaloniaDispatcher : "implements"
IUIInvoker <|.. WPFUIInvoker : "implements"
IUIInvoker <|.. AvaloniaUIInvoker : "implements"
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Detailed Component Analysis
### Dispatcher Interface and Implementations
Purpose:
- Provide a unified way to schedule work on the UI thread regardless of the underlying UI framework
- Support both synchronous and asynchronous dispatching patterns
Implementation highlights:
- WPFDispatcher bridges to WPF’s dispatcher model
- AvaloniaDispatcher bridges to Avalonia’s dispatcher model
- Both expose methods to enqueue actions and ensure they execute on the UI thread
```mermaid
sequenceDiagram
participant BG as "Background Thread"
participant Shared as "Shared Code"
participant Disp as "IDispatcher"
participant Impl as "WPFDispatcher / AvaloniaDispatcher"
participant UIThread as "UI Thread"
BG->>Shared : "Perform long-running task"
Shared->>Disp : "BeginInvoke(action)"
Disp->>Impl : "Forward call"
Impl->>UIThread : "Marshal action"
UIThread-->>Impl : "Execute action"
Impl-->>Shared : "Return"
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
### UI Invoker Interface and Implementations
Purpose:
- Encapsulate UI framework-specific invocation semantics
- Offer IsOnUIThread checks and safe InvokeOnUiThread helpers
Implementation highlights:
- WPFUIInvoker uses WPF’s thread affinity APIs
- AvaloniaUIInvoker uses Avalonia’s thread context APIs
- Shared code calls IUIInvoker without knowing the underlying framework
```mermaid
flowchart TD
Start(["Start"]) --> Check["Check if currently on UI thread"]
Check --> |Yes| ExecuteDirect["Execute UI update directly"]
Check --> |No| Enqueue["Enqueue action via dispatcher"]
Enqueue --> Wait["Wait for completion if needed"]
ExecuteDirect --> End(["End"])
Wait --> End
```
**Diagram sources**
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
**Section sources**
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
### Engine Initialization and Platform Selection
Purpose:
- Initialize the correct platform-specific dispatcher and UI invoker
- Configure application lifecycle and entry points per platform
Implementation highlights:
- Shared Engine defines common startup logic and configuration
- WPF Engine initializes WPF-specific resources and sets up WPFDispatcher/WPFUIInvoker
- Avalonia Engine initializes Avalonia-specific resources and sets up AvaloniaDispatcher/AvaloniaUIInvoker
- Avalonia Program and App coordinate bootstrapping and DI setup
```mermaid
sequenceDiagram
participant OS as "Operating System"
participant Entry as "Program.cs (Avalonia)"
participant App as "App.axaml.cs (Avalonia)"
participant Eng as "Engine.cs (Avalonia)"
participant Disp as "AvaloniaDispatcher"
participant UIInv as "AvaloniaUIInvoker"
OS->>Entry : "Launch process"
Entry->>App : "Initialize Avalonia"
App->>Eng : "Create and configure Engine"
Eng->>Disp : "Register dispatcher"
Eng->>UIInv : "Register UI invoker"
Eng-->>App : "Ready"
```
**Diagram sources**
- [Program.cs (Avalonia)](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs (Avalonia)](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Engine.cs (Avalonia)](file://ClassicAssist.Avalonia/Engine.cs)
- [Engine.cs (WPF)](file://ClassicAssist/Engine.cs)
- [Engine.cs (Shared)](file://ClassicAssist.Shared/Engine.cs)
**Section sources**
- [Engine.cs (Shared)](file://ClassicAssist.Shared/Engine.cs)
- [Engine.cs (WPF)](file://ClassicAssist/Engine.cs)
- [Engine.cs (Avalonia)](file://ClassicAssist.Avalonia/Engine.cs)
- [Program.cs (Avalonia)](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs (Avalonia)](file://ClassicAssist.Avalonia/App.axaml.cs)
### Window Management Abstraction
Purpose:
- Provide a consistent API for creating, showing, and managing windows across platforms
- Hide differences between WPF Window and Avalonia Window lifecycles
Approach:
- Use platform-specific providers registered by each Engine implementation
- Expose simple Create/Show/Close operations from shared code
Considerations:
- Ensure UI thread affinity when manipulating window state
- Handle platform differences in modal dialogs and owner relationships
[No sources needed since this section doesn't analyze specific files]
### File System Access Abstraction
Purpose:
- Normalize path separators, case sensitivity, and special directories across platforms
- Provide helper utilities for reading/writing configuration and data files
Approach:
- Use shared utility functions that adapt to platform specifics
- Centralize path resolution and normalization
Considerations:
- Respect user profile locations and sandboxing constraints
- Handle permission differences on Linux/macOS vs Windows
[No sources needed since this section doesn't analyze specific files]
### Native Interop Calls
Purpose:
- Provide a single point for platform-specific native calls
- Abstract away differences in P/Invoke signatures and availability
Approach:
- Define conditional compilation or runtime detection for available APIs
- Wrap native calls behind shared interfaces where possible
Considerations:
- Guard against missing symbols on non-Windows platforms
- Prefer managed alternatives when available
**Section sources**
- [NativeMethods.cs](file://ClassicAssist.Shared/Misc/NativeMethods.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
### Message Box Provider Abstraction
Purpose:
- Standardize user-facing dialog interactions across platforms
- Allow shared code to show messages without depending on UI framework details
Implementation highlights:
- MessageBoxProvider defines the shared contract
- WPFMessageBoxProvider implements it using WPF dialogs
- AvaloniaMessageBoxProvider implements it using Avalonia dialogs
```mermaid
classDiagram
class MessageBoxProvider {
<<interface>>
+ "Show(message)"
}
class WPFMessageBoxProvider
class AvaloniaMessageBoxProvider
MessageBoxProvider <|.. WPFMessageBoxProvider : "implements"
MessageBoxProvider <|.. AvaloniaMessageBoxProvider : "implements"
```
**Diagram sources**
- [MessageBoxProvider.cs](file://ClassicAssist.Shared/Misc/MessageBoxProvider.cs)
- [WPFMessageBoxProvider.cs](file://ClassicAssist/UI/Misc/WPFMessageBoxProvider.cs)
- [AvaloniaMessageBoxProvider.cs](file://ClassicAssist.Avalonia/Misc/AvaloniaMessageBoxProvider.cs)
**Section sources**
- [MessageBoxProvider.cs](file://ClassicAssist.Shared/Misc/MessageBoxProvider.cs)
- [WPFMessageBoxProvider.cs](file://ClassicAssist/UI/Misc/WPFMessageBoxProvider.cs)
- [AvaloniaMessageBoxProvider.cs](file://ClassicAssist.Avalonia/Misc/AvaloniaMessageBoxProvider.cs)
## Dependency Analysis
The following diagram shows how shared interfaces are implemented by platform-specific classes and how engines wire them together.
```mermaid
graph LR
Shared["Shared Interfaces<br/>IDispatcher, IUIInvoker"] --> WPFImpl["WPF Implementations<br/>WPFDispatcher, WPFUIInvoker"]
Shared --> AvaloniaImpl["Avalonia Implementations<br/>AvaloniaDispatcher, AvaloniaUIInvoker"]
SharedEng["Shared Engine"] --> WPFEng["WPF Engine"]
SharedEng --> AvaloniaEng["Avalonia Engine"]
WPFEng --> WPFImpl
AvaloniaEng --> AvaloniaImpl
```
**Diagram sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [Engine.cs (Shared)](file://ClassicAssist.Shared/Engine.cs)
- [Engine.cs (WPF)](file://ClassicAssist/Engine.cs)
- [Engine.cs (Avalonia)](file://ClassicAssist.Avalonia/Engine.cs)
**Section sources**
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFDispatcher.cs](file://ClassicAssist/WPFDispatcher.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [Engine.cs (Shared)](file://ClassicAssist.Shared/Engine.cs)
- [Engine.cs (WPF)](file://ClassicAssist/Engine.cs)
- [Engine.cs (Avalonia)](file://ClassicAssist.Avalonia/Engine.cs)
## Performance Considerations
- Minimize cross-thread marshals: batch UI updates when possible to reduce dispatcher overhead
- Avoid blocking the UI thread: use BeginInvoke-style patterns for long-running tasks
- Prefer lightweight invocations: keep actions small and focused to reduce contention
- Cache frequently accessed platform info: avoid repeated platform detection calls
- Be mindful of memory pressure: avoid capturing large objects in dispatched closures
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- Cross-thread operation exceptions: ensure all UI updates go through IUIInvoker.InvokeOnUiThread
- Deadlocks on UI thread: avoid calling synchronous Invoke from the UI thread; prefer asynchronous patterns
- Missing platform features: guard native calls with platform detection and fallbacks
- Dialog visibility problems: verify that dialogs are shown on the correct UI thread and have proper owners
**Section sources**
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [WPFUIInvoker.cs](file://ClassicAssist/WPFUIInvoker.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [PlatformDetector.cs](file://ClassicAssist.Shared/Engine/PlatformDetector.cs)
## Conclusion
The cross-platform abstraction layer cleanly separates shared logic from platform-specific concerns using well-defined interfaces for dispatching and UI invocation. By centralizing platform selection in the Engine implementations and providing consistent APIs for window management, file system access, and native interop, ClassicAssist achieves robust support across Windows, Linux, and macOS. Following the migration strategies and performance guidelines outlined here will help maintain stability and portability as the codebase evolves.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
### Migration Strategies
- Introduce new platform-specific feature:
- Add an interface method to the relevant shared interface if necessary
- Implement the method in WPF and Avalonia providers
- Update Engines to register the new provider
- Replace direct UI framework calls:
- Refactor to use IUIInvoker and IDispatcher
- Remove direct references to WPF/Avalonia types from shared code
- Handle native interop:
- Wrap calls in shared utilities with platform guards
- Provide no-op or alternative implementations for unsupported platforms
[No sources needed since this section doesn't analyze specific files]
@@ -0,0 +1,373 @@
# Custom Controls Library
<cite>
**Referenced Files in This Document**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [HuePickerWindow.axaml](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml)
- [HuePickerWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml.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 describes the custom controls library built with Avalonia, focusing on four reusable controls:
- HexDumpControl for efficient binary data visualization
- EditTextBlock for editable text display
- TextBoxKey for key binding input
- HueEntryControl for color selection (via a picker window and value converter)
It explains control properties, events, styling options, integration patterns, usage examples, customization guidelines, and performance considerations—especially for complex rendering like hex dump.
## Project Structure
The controls are implemented under ClassicAssist.Avalonia/Controls and related resources. Each control typically consists of an AXAML markup file and a code-behind file. Supporting converters and windows reside under ClassicAssist.Avalonia/Misc and ClassicAssist.Avalonia/Views.
```mermaid
graph TB
subgraph "Avalonia Controls"
HDC["HexDumpControl.axaml<br/>HexDumpControl.axaml.cs"]
EBT["EditTextBlock.axaml<br/>EditTextBlock.axaml.cs"]
TK["TextBoxKey.axaml<br/>TextBoxKey.axaml.cs"]
end
subgraph "Color Selection"
HEC["HueEntryControl (conceptual)<br/>uses HueEntryToRectanglesValueConverter"]
HPW["HuePickerWindow.axaml<br/>HuePickerWindow.axaml.cs"]
CONV["HueEntryToRectanglesValueConverter.cs"]
end
HDC --> |"renders bytes"| UI["Avalonia UI"]
EBT --> |"editable text"| UI
TK --> |"key capture"| UI
HEC --> CONV
HEC --> HPW
```
[No sources needed since this diagram shows conceptual structure]
## Core Components
- HexDumpControl: Displays large byte buffers as a scrollable grid of rows and columns with optional ASCII column, row headers, and selection support. Optimized for performance via virtualization and incremental updates.
- EditTextBlock: A read-only TextBlock that can be toggled into edit mode to allow inline editing, then committed or canceled.
- TextBoxKey: Captures keyboard input to represent key combinations (e.g., Ctrl+Shift+A), exposing a bound KeyBinding-like model.
- HueEntryControl: Presents a hue selector entry that opens a HuePickerWindow and uses a value converter to render preview rectangles based on selected hues.
Integration pattern: Bind control properties to view models using Avalonia’s two-way bindings; expose events where appropriate; style via styles and templates.
**Section sources**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [HuePickerWindow.axaml](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml)
- [HuePickerWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml.cs)
## Architecture Overview
The controls follow a standard Avalonia pattern:
- AXAML defines layout and visual tree
- Code-behind exposes dependency properties and handles events
- ViewModels bind to these properties
- Converters transform values for display
- Windows provide modal interactions (e.g., HuePickerWindow)
```mermaid
sequenceDiagram
participant VM as "ViewModel"
participant HDC as "HexDumpControl"
participant UI as "Avalonia UI"
VM->>HDC : Set Data property
HDC->>UI : Render rows/columns (virtualized)
UI-->>HDC : Scroll/Selection events
HDC-->>VM : Notify changes (events/properties)
```
**Diagram sources**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
## Detailed Component Analysis
### HexDumpControl
Purpose: Efficiently visualize large byte arrays or streams as a hex grid with optional ASCII representation and selection.
Key responsibilities:
- Accept a byte source and render it into a grid
- Support scrolling, selection, and optional ASCII column
- Provide styling hooks for colors, fonts, and cell sizes
- Expose events for user interaction (e.g., selection changed)
Typical properties and behaviors:
- Data: Source bytes or buffer
- RowCount/ColumnWidth: Layout configuration
- ShowAscii: Toggle ASCII column visibility
- SelectedRange: Current selection range
- Events: SelectionChanged, Scrolled, etc.
Styling options:
- Cell background/foreground
- Header brushes
- Selection highlight brush
- Font family and size for hex and ASCII cells
Usage example (conceptual):
- Bind Data to a byte array in your ViewModel
- Handle SelectionChanged to react to user selections
- Style via ResourceDictionary for consistent look across app
Performance considerations:
- Use virtualization to avoid creating all rows at once
- Batch updates when data changes frequently
- Avoid heavy per-cell computations; precompute if possible
- Limit visible columns to reduce layout cost
```mermaid
flowchart TD
Start(["Set Data"]) --> Validate["Validate input length"]
Validate --> InitLayout["Initialize grid layout<br/>rows/columns"]
InitLayout --> Virtualize["Enable virtualization"]
Virtualize --> Render["Render visible cells"]
Render --> Interact{"User interaction?"}
Interact --> |Scroll| UpdateVisible["Update visible viewport"]
Interact --> |Select| UpdateSelection["Update selection state"]
UpdateVisible --> Render
UpdateSelection --> Render
Interact --> |No| End(["Idle"])
Render --> End
```
**Diagram sources**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
**Section sources**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
### EditTextBlock
Purpose: Display text in a TextBlock-like control that can switch to an editable TextBox for inline editing.
Key responsibilities:
- Show text in read-only mode
- Enter edit mode on demand (e.g., double-click)
- Commit or cancel edits
- Keep content synchronized with a bound property
Typical properties and behaviors:
- Text: Two-way bound text content
- IsEditable: Toggle editability
- EditModeTrigger: Event or command to enter edit mode
- Events: EditingStarted, EditingEnded, TextChanged
Styling options:
- Read-only appearance (font, padding)
- Edit mode appearance (border, focus visuals)
- Placeholder text styling
Usage example (conceptual):
- Bind Text to a string property in ViewModel
- Trigger edit mode via command or gesture
- On commit, update ViewModel; on cancel, revert
```mermaid
sequenceDiagram
participant User as "User"
participant EBT as "EditTextBlock"
participant VM as "ViewModel"
User->>EBT : Double-click to edit
EBT->>EBT : Enter edit mode
User->>EBT : Type new text
EBT->>VM : Update bound Text (two-way)
User->>EBT : Press Enter or lose focus
EBT->>EBT : Exit edit mode
EBT-->>VM : Commit final value
```
**Diagram sources**
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
**Section sources**
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
### TextBoxKey
Purpose: Capture keyboard input to represent key combinations for hotkeys or shortcuts.
Key responsibilities:
- Capture key presses and modifiers
- Format the combination into a readable string
- Expose a bound KeyBinding-like model
- Prevent default actions when capturing
Typical properties and behaviors:
- KeyText: Displayed key combination string
- Modifiers: Captured modifier keys
- Events: KeyCaptured, ValidationFailed
Styling options:
- Input border and focus visuals
- Error state styling (invalid combinations)
Usage example (conceptual):
- Bind KeyText to a string property in ViewModel
- On capture, validate combination and notify ViewModel
- Provide clear feedback for invalid inputs
```mermaid
flowchart TD
Start(["Focus TextBoxKey"]) --> Press["User presses keys"]
Press --> Capture["Capture key and modifiers"]
Capture --> Validate{"Valid combination?"}
Validate --> |Yes| Update["Update KeyText and notify"]
Validate --> |No| Error["Show validation error"]
Update --> End(["Ready"])
Error --> End
```
**Diagram sources**
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
**Section sources**
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
### HueEntryControl
Purpose: Provide a compact entry for selecting hues, opening a HuePickerWindow and rendering previews using a value converter.
Key responsibilities:
- Open HuePickerWindow to select hue(s)
- Convert selected hues to visual rectangles for preview
- Expose selected hue values to ViewModel
Typical properties and behaviors:
- SelectedHues: Collection of selected hues
- PreviewBrushes: Converted brushes for preview
- Events: HueSelected, PickerClosed
Styling options:
- Entry border and focus visuals
- Preview rectangle size and spacing
- Picker button styling
Usage example (conceptual):
- Bind SelectedHues to a collection in ViewModel
- Use HueEntryToRectanglesValueConverter to render preview rectangles
- Handle HueSelected to update UI or settings
```mermaid
classDiagram
class HueEntryControl {
+SelectedHues
+PreviewBrushes
+OpenPicker()
}
class HueEntryToRectanglesValueConverter {
+Convert(value)
}
class HuePickerWindow {
+OnHueSelected(hue)
}
HueEntryControl --> HueEntryToRectanglesValueConverter : "uses"
HueEntryControl --> HuePickerWindow : "opens"
```
**Diagram sources**
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [HuePickerWindow.axaml](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml)
- [HuePickerWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml.cs)
**Section sources**
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [HuePickerWindow.axaml](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml)
- [HuePickerWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml.cs)
## Dependency Analysis
- HexDumpControl depends on Avalonia’s ItemsControl/Grid infrastructure and may rely on virtualization features for performance.
- EditTextBlock composes TextBlock and TextBox internally, switching visibility based on edit mode.
- TextBoxKey listens to low-level keyboard events and formats them into a display string.
- HueEntryControl depends on HueEntryToRectanglesValueConverter and HuePickerWindow for selection and preview.
```mermaid
graph LR
HDC["HexDumpControl"] --> AV["Avalonia Grid/ItemsControl"]
EBT["EditTextBlock"] --> TB["TextBox"]
EBT --> TBLK["TextBlock"]
TK["TextBoxKey"] --> KEV["Keyboard Events"]
HEC["HueEntryControl"] --> CONV["HueEntryToRectanglesValueConverter"]
HEC --> HPW["HuePickerWindow"]
```
**Diagram sources**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [HuePickerWindow.axaml](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml)
**Section sources**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [HuePickerWindow.axaml](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml)
## Performance Considerations
- HexDumpControl:
- Enable virtualization to avoid creating off-screen elements
- Batch updates by replacing entire data sets rather than mutating large collections incrementally
- Precompute ASCII representations if needed
- Limit column count and adjust cell width to balance readability and performance
- Debounce rapid data changes to reduce re-render frequency
- EditTextBlock:
- Avoid unnecessary rebinds during edit sessions
- Use lightweight validation to prevent expensive checks on every keystroke
- TextBoxKey:
- Minimize event handling overhead; only process relevant key combinations
- Cache formatted strings for repeated combinations
- HueEntryControl:
- Convert hues to brushes lazily and cache results
- Limit number of preview rectangles to maintain responsiveness
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- HexDumpControl not updating:
- Ensure Data property is set on the UI thread
- Verify virtualization is enabled and items panel supports recycling
- EditTextBlock not committing edits:
- Check focus management and blur handlers
- Confirm two-way binding path is correct
- TextBoxKey capturing wrong keys:
- Validate modifier key detection logic
- Ensure default actions are prevented during capture
- HueEntryControl preview not showing:
- Verify converter returns valid brushes
- Confirm HuePickerWindow closes with selected hue and notifies control
**Section sources**
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [HuePickerWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/HuePickerWindow.axaml.cs)
## Conclusion
The custom controls library provides robust, reusable components for common UI tasks in Avalonia applications. By leveraging dependency properties, events, and converters, each control integrates cleanly with MVVM patterns. For high-performance scenarios like hex dump rendering, prioritize virtualization and batch updates. Consistent styling and clear integration patterns ensure maintainability and extensibility across the application.
[No sources needed since this section summarizes without analyzing specific files]
@@ -0,0 +1,530 @@
# MVVM Architecture 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)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.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)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
- [AutolootViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/AutolootViewModel.cs)
- [DressTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/DressTabViewModel.cs)
- [FriendsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/FriendsTabViewModel.cs)
- [OrganizerTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/OrganizerTabViewModel.cs)
- [ScavengerTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/ScavengerTabViewModel.cs)
- [VendorBuyTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/VendorBuyTabViewModel.cs)
- [VendorSellTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/VendorSellTabViewModel.cs)
- [ClilocSelectionViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/ClilocSelectionViewModel.cs)
- [CustomPropertiesViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/CustomPropertiesViewModel.cs)
- [PropertySelectionViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/PropertySelectionViewModel.cs)
- [AboutControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/AboutControlViewModel.cs)
- [DebugViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/DebugViewModel.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
- [HotkeyEntryViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/HotkeyEntryViewModel.cs)
- [HotkeysTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/HotkeysTabViewModel.cs)
- [MacrosTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MacrosTabViewModel.cs)
- [NewProfileViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/NewProfileViewModel.cs)
- [ObjectInspectorViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/ObjectInspectorViewModel.cs)
- [OptionsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/OptionsTabViewModel.cs)
- [RepositionableGumpViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/RepositionableGumpViewModel.cs)
- [SkillsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/SkillsTabViewModel.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [ChatMessage.cs](file://ClassicAssist.Shared/Data/Chat/ChatMessage.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.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 Model-View-ViewModel (MVVM) architecture implemented in ClassicAssist.Avalonia. It focuses on separation of concerns between Views (XAML), ViewModels (C# logic), and Models (data), with emphasis on:
- BaseViewModel hierarchy and property change notification patterns
- Command binding mechanisms
- Data flow from game engine through ViewModels to UI components
- ViewModel composition, dependency injection, and lifecycle management
- Error handling strategies, validation patterns, and testing approaches for MVVM components
The goal is to provide a clear mental model for both new contributors and experienced developers working on the Avalonia-based UI layer.
## Project Structure
The project follows a layered structure:
- Shared core (models, services, commands, base MVVM infrastructure)
- Avalonia-specific presentation layer (Views, ViewModels, converters, behaviors)
- Game engine integration points (networking, packets, UO data)
```mermaid
graph TB
subgraph "Shared Core"
VM_Base["BaseViewModel"]
VM_Main["MainWindowViewModel"]
VM_Agents["Agent Tab ViewModels"]
VM_Autoloot["Autoloot ViewModels"]
VM_Others["Other ViewModels"]
ChatMgr["ChatManager"]
Incoming["IncomingPacketHandlers"]
end
subgraph "Avalonia UI"
App["App.axaml.cs"]
Program["Program.cs"]
MainWindow["MainWindow.axaml.cs"]
Dispatcher["AvaloniaDispatcher"]
UIInvoker["AvaloniaUIInvoker"]
end
Program --> App
App --> MainWindow
MainWindow --> VM_Main
VM_Main --> VM_Agents
VM_Main --> VM_Autoloot
VM_Main --> VM_Others
VM_Agents --> ChatMgr
VM_Autoloot --> ChatMgr
VM_Others --> ChatMgr
Incoming --> ChatMgr
VM_Main --> Dispatcher
VM_Main --> UIInvoker
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.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)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.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)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
## Core Components
- BaseViewModel: Provides common MVVM infrastructure such as property change notification and command support. All ViewModels derive from this class to ensure consistent behavior.
- MainWindowViewModel: Orchestrates top-level UI state and composes child ViewModels for tabs and features.
- AvaloniaDispatcher and AvaloniaUIInvoker: Implement shared interfaces to marshal work onto the UI thread and present UI interactions (e.g., dialogs).
- ChatManager and related models: Centralize chat-related data and events that ViewModels consume.
Key responsibilities:
- BaseViewModel encapsulates INotifyPropertyChanged semantics and command execution helpers.
- MainWindowViewModel wires together tab ViewModels and exposes them to the view via bindings.
- Dispatcher and UIInvoker abstract platform-specific threading and UI operations.
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.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)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
## Architecture Overview
The MVVM layers are cleanly separated:
- Views (AXAML + code-behind) bind to properties and commands exposed by ViewModels.
- ViewModels contain presentation logic, coordinate with models/services, and raise property change notifications.
- Models represent domain data and business rules; they may publish events or expose collections that ViewModels observe.
```mermaid
sequenceDiagram
participant Engine as "Game Engine"
participant Incoming as "IncomingPacketHandlers"
participant ChatMgr as "ChatManager"
participant VM as "ViewModel (e.g., ChatViewModel)"
participant View as "Avalonia View"
Engine->>Incoming : "Parse incoming packet"
Incoming->>ChatMgr : "Update chat state / raise event"
ChatMgr-->>VM : "Notify changes (events/collections)"
VM->>VM : "Update bound properties"
VM-->>View : "INotifyPropertyChanged triggers UI update"
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
## Detailed Component Analysis
### BaseViewModel Hierarchy and Property Change Notification
BaseViewModel centralizes:
- Property change notification implementation
- Common command helpers and execution context
- Lifecycle hooks used by derived ViewModels
Derived ViewModels inherit these capabilities and focus on feature-specific logic.
```mermaid
classDiagram
class BaseViewModel {
+OnInitialized()
+OnDisposed()
+RaisePropertyChanged(propertyName)
+ExecuteCommand(command)
}
class MainWindowViewModel {
+Tabs
+ActiveTab
+Initialize()
}
class AutolootViewModel
class DressTabViewModel
class FriendsTabViewModel
class OrganizerTabViewModel
class ScavengerTabViewModel
class VendorBuyTabViewModel
class VendorSellTabViewModel
class ClilocSelectionViewModel
class CustomPropertiesViewModel
class PropertySelectionViewModel
class AboutControlViewModel
class DebugViewModel
class GeneralControlViewModel
class HotkeyEntryViewModel
class HotkeysTabViewModel
class MacrosTabViewModel
class NewProfileViewModel
class ObjectInspectorViewModel
class OptionsTabViewModel
class RepositionableGumpViewModel
class SkillsTabViewModel
class DialogWindowViewModel
MainWindowViewModel --|> BaseViewModel
AutolootViewModel --|> BaseViewModel
DressTabViewModel --|> BaseViewModel
FriendsTabViewModel --|> BaseViewModel
OrganizerTabViewModel --|> BaseViewModel
ScavengerTabViewModel --|> BaseViewModel
VendorBuyTabViewModel --|> BaseViewModel
VendorSellTabViewModel --|> BaseViewModel
ClilocSelectionViewModel --|> BaseViewModel
CustomPropertiesViewModel --|> BaseViewModel
PropertySelectionViewModel --|> BaseViewModel
AboutControlViewModel --|> BaseViewModel
DebugViewModel --|> BaseViewModel
GeneralControlViewModel --|> BaseViewModel
HotkeyEntryViewModel --|> BaseViewModel
HotkeysTabViewModel --|> BaseViewModel
MacrosTabViewModel --|> BaseViewModel
NewProfileViewModel --|> BaseViewModel
ObjectInspectorViewModel --|> BaseViewModel
OptionsTabViewModel --|> BaseViewModel
RepositionableGumpViewModel --|> BaseViewModel
SkillsTabViewModel --|> BaseViewModel
DialogWindowViewModel --|> BaseViewModel
```
**Diagram sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [AutolootViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/AutolootViewModel.cs)
- [DressTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/DressTabViewModel.cs)
- [FriendsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/FriendsTabViewModel.cs)
- [OrganizerTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/OrganizerTabViewModel.cs)
- [ScavengerTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/ScavengerTabViewModel.cs)
- [VendorBuyTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/VendorBuyTabViewModel.cs)
- [VendorSellTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/VendorSellTabViewModel.cs)
- [ClilocSelectionViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/ClilocSelectionViewModel.cs)
- [CustomPropertiesViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/CustomPropertiesViewModel.cs)
- [PropertySelectionViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/PropertySelectionViewModel.cs)
- [AboutControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/AboutControlViewModel.cs)
- [DebugViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/DebugViewModel.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
- [HotkeyEntryViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/HotkeyEntryViewModel.cs)
- [HotkeysTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/HotkeysTabViewModel.cs)
- [MacrosTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MacrosTabViewModel.cs)
- [NewProfileViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/NewProfileViewModel.cs)
- [ObjectInspectorViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/ObjectInspectorViewModel.cs)
- [OptionsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/OptionsTabViewModel.cs)
- [RepositionableGumpViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/RepositionableGumpViewModel.cs)
- [SkillsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/SkillsTabViewModel.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [AutolootViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/AutolootViewModel.cs)
- [DressTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/DressTabViewModel.cs)
- [FriendsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/FriendsTabViewModel.cs)
- [OrganizerTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/OrganizerTabViewModel.cs)
- [ScavengerTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/ScavengerTabViewModel.cs)
- [VendorBuyTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/VendorBuyTabViewModel.cs)
- [VendorSellTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Agents/VendorSellTabViewModel.cs)
- [ClilocSelectionViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/ClilocSelectionViewModel.cs)
- [CustomPropertiesViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/CustomPropertiesViewModel.cs)
- [PropertySelectionViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/Autoloot/PropertySelectionViewModel.cs)
- [AboutControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/AboutControlViewModel.cs)
- [DebugViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/DebugViewModel.cs)
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
- [HotkeyEntryViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/HotkeyEntryViewModel.cs)
- [HotkeysTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/HotkeysTabViewModel.cs)
- [MacrosTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MacrosTabViewModel.cs)
- [NewProfileViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/NewProfileViewModel.cs)
- [ObjectInspectorViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/ObjectInspectorViewModel.cs)
- [OptionsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/OptionsTabViewModel.cs)
- [RepositionableGumpViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/RepositionableGumpViewModel.cs)
- [SkillsTabViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/SkillsTabViewModel.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
### Command Binding Mechanisms
Commands in ViewModels encapsulate user actions and are bound directly in XAML. Typical patterns include:
- Defining command properties on ViewModels
- Executing asynchronous operations safely on background threads
- Marshaling results back to the UI thread using the dispatcher abstraction
```mermaid
flowchart TD
Start(["User Action"]) --> Bind["XAML binds to ViewModel.Command"]
Bind --> Execute["ViewModel executes command"]
Execute --> Validate["Validate inputs"]
Validate --> Valid{"Valid?"}
Valid --> |No| ShowError["Show error via UIInvoker"]
Valid --> |Yes| DoWork["Perform background work"]
DoWork --> UpdateUI["Marshal result to UI thread"]
UpdateUI --> End(["UI updates via properties"])
ShowError --> End
```
**Diagram sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.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)
**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)
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
### Data Flow from Game Engine to UI
Incoming network packets are processed by handlers, which update shared managers (e.g., ChatManager). ViewModels subscribe to manager events or observe collections, then update their own properties. The UI reacts automatically due to property change notifications.
```mermaid
sequenceDiagram
participant Net as "Network Layer"
participant Handler as "IncomingPacketHandlers"
participant Packet as "Packets (e.g., MobileIncoming, UseObject)"
participant Manager as "ChatManager"
participant VM as "ViewModel"
participant View as "Avalonia View"
Net->>Handler : "Receive packet bytes"
Handler->>Packet : "Deserialize packet"
Packet->>Manager : "Apply changes / raise events"
Manager-->>VM : "Notify subscribers"
VM->>VM : "Update bound properties"
VM-->>View : "INotifyPropertyChanged"
View-->>View : "Render updated UI"
```
**Diagram sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
**Section sources**
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
- [MobileIncoming.cs](file://ClassicAssist.Shared/UO/Network/Packets/MobileIncoming.cs)
- [UseObject.cs](file://ClassicAssist.Shared/UO/Network/Packets/UseObject.cs)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
### ViewModel Composition and Dependency Injection
Composition occurs at application startup:
- Program initializes the application framework
- App configures services and creates root ViewModels
- MainWindow sets its DataContext to the root ViewModel
- Child ViewModels are composed into parent ViewModels (e.g., tabs)
```mermaid
sequenceDiagram
participant Main as "Program.Main"
participant App as "App"
participant Window as "MainWindow"
participant RootVM as "MainWindowViewModel"
participant ChildVM as "Child ViewModel(s)"
Main->>App : "Run()"
App->>App : "Configure DI / services"
App->>RootVM : "Create root ViewModel"
App->>Window : "Create main window"
Window->>Window : "Set DataContext = RootVM"
RootVM->>ChildVM : "Compose child ViewModels"
Window-->>Window : "Bind to RootVM and children"
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
### Lifecycle Management
Typical lifecycle stages:
- Initialization: ViewModels set up subscriptions, load configuration, and prepare initial state
- Active: ViewModels respond to user input and engine events
- Disposal: ViewModels unsubscribe from events and release resources
BaseViewModel provides hooks for initialization and disposal. Ensure all long-lived subscriptions are cleaned up to prevent memory leaks.
```mermaid
stateDiagram-v2
[*] --> Created
Created --> Initialized : "OnInitialized"
Initialized --> Active : "Bound to View"
Active --> Disposing : "OnDisposed"
Disposing --> [*]
```
**Diagram sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
### Error Handling Strategies
- Commands should catch exceptions and report errors via UIInvoker
- Validation failures should be surfaced to users promptly
- Background tasks must marshal exceptions back to the UI thread before reporting
```mermaid
flowchart TD
Entry(["Command Entry"]) --> TryBlock["Try block"]
TryBlock --> Success{"Success?"}
Success --> |Yes| Done(["Return success"])
Success --> |No| Catch["Catch exception"]
Catch --> Marshal["Marshal to UI thread"]
Marshal --> Report["Report via UIInvoker"]
Report --> Done
```
**Diagram sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
**Section sources**
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
### Validation Patterns
- Input validation within commands before executing side effects
- Property setters can validate and raise property change notifications only when valid
- Use centralized validation helpers where appropriate to keep ViewModels focused
[No sources needed since this section provides general guidance]
### Testing Approaches for MVVM Components
- Unit test ViewModels without UI dependencies by mocking IDispatcher and IUIInvoker
- Assert property change notifications and command outcomes
- Simulate engine events by invoking manager methods and verifying ViewModel state changes
[No sources needed since this section provides general guidance]
## Dependency Analysis
The following diagram shows key runtime dependencies among MVVM components and UI abstractions.
```mermaid
graph LR
Program["Program.cs"] --> App["App.axaml.cs"]
App --> MainWindow["MainWindow.axaml.cs"]
MainWindow --> MainWindowVM["MainWindowViewModel.cs"]
MainWindowVM --> BaseVM["BaseViewModel.cs"]
MainWindowVM --> Dispatcher["AvaloniaDispatcher.cs"]
MainWindowVM --> UIInvoker["AvaloniaUIInvoker.cs"]
Dispatcher --> IDisp["IDispatcher.cs"]
UIInvoker --> IUI["IUIInvoker.cs"]
MainWindowVM --> ChatMgr["ChatManager.cs"]
Incoming["IncomingPacketHandlers.cs"] --> ChatMgr
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.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)
- [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)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.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)
- [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)
- [ChatManager.cs](file://ClassicAssist.Shared/Data/Chat/ChatManager.cs)
- [IncomingPacketHandlers.cs](file://ClassicAssist.Shared/UO/Network/IncomingPacketHandlers.cs)
## Performance Considerations
- Minimize heavy work on the UI thread; use background tasks and marshal results back via the dispatcher
- Avoid excessive property change notifications by batching updates where possible
- Use virtualization-friendly collections for large lists in views
- Dispose subscriptions and timers in ViewModels to prevent memory growth over time
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and resolutions:
- UI not updating after property changes: verify property change notifications are raised and bound correctly
- Cross-thread exceptions: ensure UI updates are marshaled through the dispatcher
- Memory leaks: confirm ViewModels unsubscribe from long-lived events during disposal
- Errors not shown to users: check that exceptions are caught and reported via UIInvoker
**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 a clean MVVM architecture with a strong separation of concerns. BaseViewModel standardizes property change notification and command execution, while ViewModels compose feature-specific logic and interact with shared managers. The dispatcher and UI invoker abstractions decouple UI threading and interaction details, enabling robust error handling and testability. Following the patterns outlined here will help maintain consistency, performance, and reliability across the UI layer.
## Appendices
- Additional ViewModels referenced in this document:
- Agents: Autoloot, Dress, Friends, Organizer, Scavenger, Vendor Buy/Sell
- Autoloot: Cliloc Selection, Custom Properties, Property Selection
- Other: About, Debug, General, Hotkeys, Macros, New Profile, Object Inspector, Options, Repositionable Gump, Skills
- Dialog: DialogWindowViewModel
[No sources needed since this section summarizes references already cited above]
@@ -0,0 +1,395 @@
# Theming and Styling System
<cite>
**Referenced Files in This Document**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Icons.xaml](file://ClassicAssist.Avalonia/Assets/Icons.xaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [ResourceDictionary.xaml](file://ClassicAssist/Resources/ResourceDictionary.xaml)
- [Colours.xaml](file://ClassicAssist/Resources/Colours.xaml)
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
</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 theming and styling system used by ClassicAssist.Avalonia. It covers how resource dictionaries are organized, how color schemes and themes are defined and switched, how icons are implemented, how fonts are managed, and what cross-platform considerations apply. It also provides guidance for creating custom themes, overriding default styles, implementing responsive design patterns, and building dynamic theme switching with style inheritance hierarchies.
## Project Structure
The Avalonia UI layer is organized into Views, Controls, Assets, and App-level configuration. Theming-related resources live both at the application level (Avalonia project) and within shared resources (ClassicAssist project). The main entry point configures global styles and resources.
```mermaid
graph TB
subgraph "Avalonia App"
A["App.axaml"]
B["App.axaml.cs"]
C["Assets/Icons.xaml"]
D["Controls/GroupBox.Theme.xaml"]
E["Views/MainWindow.axaml"]
F["Views/DialogWindow.axaml"]
end
subgraph "Shared Resources"
G["Resources/ResourceDictionary.xaml"]
H["Resources/Colours.xaml"]
I["Resources/DarkTheme.xaml"]
end
A --> C
A --> D
A --> G
A --> H
A --> I
E --> A
F --> A
```
**Diagram sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Icons.xaml](file://ClassicAssist.Avalonia/Assets/Icons.xaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [ResourceDictionary.xaml](file://ClassicAssist/Resources/ResourceDictionary.xaml)
- [Colours.xaml](file://ClassicAssist/Resources/Colours.xaml)
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [Icons.xaml](file://ClassicAssist.Avalonia/Assets/Icons.xaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [ResourceDictionary.xaml](file://ClassicAssist/Resources/ResourceDictionary.xaml)
- [Colours.xaml](file://ClassicAssist/Resources/Colours.xaml)
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
## Core Components
- Application-level resource dictionary: Centralizes merged dictionaries for colors, themes, icons, and control-specific themes.
- Color scheme definitions: Shared color tokens that can be reused across controls and views.
- Theme definitions: Named sets of resources (colors, brushes, etc.) that can be swapped at runtime.
- Icon system: A centralized icon dictionary referenced by views and controls.
- Control-level themes: Per-control theme dictionaries to override defaults consistently.
- View integration: Views reference theme resources via static resources or themed bindings.
Key responsibilities:
- App.axaml merges all theme-related dictionaries and exposes them globally.
- ResourceDictionary.xaml aggregates shared resources from multiple files.
- Colours.xaml defines semantic color tokens.
- DarkTheme.xaml provides a complete dark theme set.
- Icons.xaml defines reusable vector/icon resources.
- GroupBox.Theme.xaml demonstrates control-level theme overrides.
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [ResourceDictionary.xaml](file://ClassicAssist/Resources/ResourceDictionary.xaml)
- [Colours.xaml](file://ClassicAssist/Resources/Colours.xaml)
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [Icons.xaml](file://ClassicAssist.Avalonia/Assets/Icons.xaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
## Architecture Overview
The theming architecture follows a layered approach:
- Global app resources define base tokens and merged dictionaries.
- Themes provide named resource sets that can be applied dynamically.
- Control-level themes refine appearance for specific components.
- Views consume resources through static references and data binding.
```mermaid
sequenceDiagram
participant App as "App.axaml"
participant Merged as "Merged Dictionaries"
participant Colors as "Colours.xaml"
participant Theme as "DarkTheme.xaml"
participant Icons as "Icons.xaml"
participant ControlTheme as "GroupBox.Theme.xaml"
participant View as "MainWindow.axaml"
App->>Merged : "Merge theme resources"
Merged->>Colors : "Load color tokens"
Merged->>Theme : "Load theme palette"
Merged->>Icons : "Load icon definitions"
Merged->>ControlTheme : "Load control overrides"
View->>Merged : "Resolve resources via StaticResource"
Note over View,Merged : "View uses theme tokens and icons"
```
**Diagram sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [ResourceDictionary.xaml](file://ClassicAssist/Resources/ResourceDictionary.xaml)
- [Colours.xaml](file://ClassicAssist/Resources/Colours.xaml)
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [Icons.xaml](file://ClassicAssist.Avalonia/Assets/Icons.xaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
## Detailed Component Analysis
### Resource Dictionary Structure
- Aggregation: A central dictionary merges multiple theme-related dictionaries to keep resources modular and maintainable.
- Scope: Resources are available application-wide when merged at the app level; local scopes can override as needed.
- Organization: Semantic tokens (colors), theme palettes (dark/light), icons, and control-specific themes are separated into distinct files.
Practical implications:
- Adding a new theme involves creating a new theme dictionary and merging it at the app level.
- Overriding a single token is straightforward by redefining the key in a higher-priority dictionary.
**Section sources**
- [ResourceDictionary.xaml](file://ClassicAssist/Resources/ResourceDictionary.xaml)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
### Color Schemes and Theme Definitions
- Color tokens: Defined in a dedicated file to ensure consistency across the UI.
- Theme sets: Provide complete palettes (e.g., dark theme) including background, foreground, accent, and state colors.
- Switching mechanism: At runtime, replace the active theme dictionary or update resource keys to reflect the selected theme.
Guidelines:
- Use semantic keys rather than hard-coded values.
- Keep theme dictionaries self-contained and keyed consistently.
- Ensure contrast and accessibility requirements are met for each theme.
**Section sources**
- [Colours.xaml](file://ClassicAssist/Resources/Colours.xaml)
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
### Theme Switching Mechanisms
Two common approaches:
- Dictionary replacement: Swap the active theme dictionary in the merged resources collection.
- Resource key updates: Update specific resource keys (e.g., colors) to reflect the new theme without full replacement.
Implementation notes:
- Perform theme changes on the UI thread to avoid synchronization issues.
- Ensure views resolve resources after the change; most XAML-based frameworks automatically refresh when resources change.
Example flow:
```mermaid
flowchart TD
Start(["User selects theme"]) --> Choose["Determine target theme"]
Choose --> Replace{"Replace dictionary<br/>or update keys?"}
Replace --> |Replace| MergeUpdate["Update merged dictionaries"]
Replace --> |Update Keys| KeyUpdate["Set new values for resource keys"]
MergeUpdate --> Refresh["UI resolves updated resources"]
KeyUpdate --> Refresh
Refresh --> End(["Theme applied"])
```
[No diagram sources since this is a conceptual flow]
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
### Icon System Implementation
- Centralized icons: Icons are defined in a dedicated dictionary and referenced by name across views and controls.
- Usage pattern: References use static resource lookups by icon key.
- Extensibility: New icons are added to the icon dictionary and consumed via their keys.
Best practices:
- Keep icon assets consistent in size and style.
- Prefer vector formats where possible for scalability.
- Avoid duplicating icon definitions; always reference the central dictionary.
**Section sources**
- [Icons.xaml](file://ClassicAssist.Avalonia/Assets/Icons.xaml)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
### Font Management
- Fonts should be embedded as Avalonia resources and referenced by family name.
- Use consistent font families across themes to maintain readability.
- For cross-platform compatibility, verify font availability and fallbacks.
Recommendations:
- Define font family tokens in resources for easy overrides.
- Test rendering on Windows, macOS, and Linux to ensure consistent appearance.
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
### Cross-Platform Styling Considerations
- Platform differences: Window chrome, DPI scaling, and font rendering vary across platforms.
- Responsive behavior: Use relative sizing and flexible layouts to adapt to different screen sizes and densities.
- Accessibility: Ensure sufficient contrast and scalable text across themes.
Guidance:
- Avoid platform-specific assumptions in shared resources.
- Validate visual fidelity on each target OS during development.
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
### Creating Custom Themes
Steps:
1. Create a new theme dictionary with consistent resource keys.
2. Define color tokens and any control-specific overrides.
3. Merge the new theme dictionary at the app level.
4. Provide a runtime switch to activate the new theme.
Tips:
- Mirror existing theme structure for predictability.
- Test all major views and controls under the new theme.
**Section sources**
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
### Overriding Default Styles
Approaches:
- Control-level theme dictionaries: Override styles for specific controls (e.g., GroupBox).
- Local scope overrides: Apply style overrides within a view’s resource scope.
- Global overrides: Redefine resource keys at the app level to affect all instances.
Example focus:
- GroupBox theme overrides demonstrate targeted control customization.
**Section sources**
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
### Implementing Responsive Design Patterns
Patterns:
- Use flexible panels and grid layouts to adapt to window resizing.
- Leverage Avalonia’s built-in layout primitives for responsiveness.
- Adjust spacing and typography based on available space.
Validation:
- Test on various resolutions and DPI settings.
- Ensure content remains readable and accessible.
**Section sources**
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
### Dynamic Theme Switching Example Flow
Runtime sequence:
```mermaid
sequenceDiagram
participant User as "User"
participant View as "MainWindow.axaml"
participant App as "App.axaml.cs"
participant Res as "Resources"
User->>View : "Select theme option"
View->>App : "Invoke theme switch command"
App->>Res : "Update merged dictionaries / resource keys"
Res-->>View : "Resources refreshed"
View-->>User : "New theme applied"
```
**Diagram sources**
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
### Style Inheritance Hierarchies
Conceptual hierarchy:
- Base tokens (colors, fonts)
- Theme palettes (dark/light)
- Control-level themes (control-specific overrides)
- View-level overrides (local scope)
```mermaid
classDiagram
class BaseTokens {
+Color Primary
+Color Secondary
+FontFamily Main
}
class DarkTheme {
+Brush Background
+Brush Foreground
+Brush Accent
}
class ControlThemes {
+Style GroupBox
+Style Button
}
class ViewOverrides {
+Local ResourceScope
}
DarkTheme --> BaseTokens : "extends"
ControlThemes --> DarkTheme : "uses"
ViewOverrides --> ControlThemes : "overrides"
```
[No diagram sources since this is a conceptual hierarchy]
## Dependency Analysis
The theming system depends on a clear separation between resources and views:
- App-level merges orchestrate resource loading order.
- Theme dictionaries depend on base tokens.
- Control themes depend on theme palettes.
- Views depend on resolved resources.
```mermaid
graph LR
Tokens["Base Tokens (Colours.xaml)"] --> Theme["Theme (DarkTheme.xaml)"]
Theme --> ControlTheme["Control Theme (GroupBox.Theme.xaml)"]
ControlTheme --> View["Views (MainWindow.axaml, DialogWindow.axaml)"]
Icons["Icons (Icons.xaml)"] --> View
App["App.axaml"] --> Tokens
App --> Theme
App --> ControlTheme
App --> Icons
```
**Diagram sources**
- [Colours.xaml](file://ClassicAssist/Resources/Colours.xaml)
- [DarkTheme.xaml](file://ClassicAssist/Resources/DarkTheme.xaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [Icons.xaml](file://ClassicAssist.Avalonia/Assets/Icons.xaml)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [ResourceDictionary.xaml](file://ClassicAssist/Resources/ResourceDictionary.xaml)
## Performance Considerations
- Minimize resource churn: Prefer replacing entire theme dictionaries rather than updating many individual keys when switching themes.
- Cache frequently used resources: Let the framework handle caching; avoid redundant lookups in code-behind.
- Optimize icon assets: Use vector icons to reduce memory footprint and improve scaling performance.
- Avoid heavy animations during theme switches to maintain responsiveness.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
Common issues and remedies:
- Missing resource keys: Ensure all referenced keys exist in the active theme dictionary.
- Incorrect merge order: Verify that base tokens are merged before theme palettes and control themes.
- Platform-specific rendering differences: Validate fonts and DPI scaling on each target OS.
- Runtime theme not applying: Confirm that resource updates occur on the UI thread and that views resolve resources after updates.
Diagnostic steps:
- Inspect merged dictionaries at runtime to confirm presence of required keys.
- Temporarily revert to a known-good theme to isolate regressions.
- Check for typos in resource keys and file paths.
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
## Conclusion
ClassicAssist.Avalonia’s theming system leverages a modular resource dictionary structure, semantic color tokens, and theme palettes to enable consistent and extensible styling. By separating concerns—base tokens, theme sets, control-level themes, and view usage—the system supports dynamic theme switching, easy customization, and cross-platform consistency. Following the guidelines here will help you create robust custom themes, override styles effectively, and implement responsive designs.
[No sources needed since this section summarizes without analyzing specific files]
## Appendices
- Quick checklist for adding a new theme:
- Create a new theme dictionary with consistent keys.
- Merge it at the app level.
- Provide a runtime switch to activate it.
- Validate across views and platforms.
[No sources needed since this section provides general guidance]
@@ -0,0 +1,513 @@
# UI Framework
<cite>
**Referenced Files in This Document**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [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)
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [GroupBox.cs](file://ClassicAssist.Avalonia/Controls/GroupBox.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvalonEditBehaviour.cs](file://ClassicAssist.Avalonia/Misc/AvalonEditBehaviour.cs)
- [CloseOnClickBehaviour.cs](file://ClassicAssist.Avalonia/Misc/CloseOnClickBehaviour.cs)
- [ComboBoxBehavior.cs](file://ClassicAssist.Avalonia/Misc/ComboBoxBehavior.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [InverseBooleanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [ListBoxAutoScrollBehaviour.cs](file://ClassicAssist.Avalonia/Misc/ListBoxAutoScrollBehaviour.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [PacketEntryBinaryValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryBinaryValueConverter.cs)
- [PacketEntryTextValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryTextValueConverter.cs)
- [StringToResourceConverter.cs](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [WindowInitializedBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowInitializedBehaviour.cs)
- [WindowResizeBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowResizeBehaviour.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.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)
</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 describes the UI framework implementation for ClassicAssist.Avalonia, focusing on the MVVM architecture with Avalonia UI, cross-platform abstractions, theme and styling, custom controls, binding system, behaviors, performance strategies, and window management. It provides a clear separation between Views, ViewModels, and Models, and explains how platform-specific implementations are abstracted to support multiple targets consistently.
## Project Structure
The UI layer is organized into distinct folders that reflect MVVM responsibilities:
- Controls: Reusable UI components (e.g., HexDumpControl, EditTextBlock, TextBoxKey).
- Views: Window and page-level XAML views bound to ViewModels.
- ViewModels: Presentation logic and state exposed to Views.
- Misc: Behaviors, value converters, and cross-cutting utilities.
- App entry points: Application lifecycle and resource initialization.
```mermaid
graph TB
subgraph "Avalonia UI"
Program["Program.cs"]
App["App.axaml / App.axaml.cs"]
MainWindow["Views/MainWindow.axaml(.cs)"]
DialogWindow["Views/DialogWindow.axaml(.cs)"]
end
subgraph "Shared UI Contracts"
IDisp["IDispatcher.cs"]
IInv["IUIInvoker.cs"]
BaseVM["Shared/UI/ViewModels/BaseViewModel.cs"]
MainVM["Shared/UI/ViewModels/MainWindowViewModel.cs"]
end
subgraph "Custom Controls"
Hex["Controls/HexDumpControl.axaml(.cs)"]
EditTxt["Controls/EditTextBlock.axaml(.cs)"]
TxtKey["Controls/TextBoxKey.axaml(.cs)"]
GroupBox["Controls/GroupBox.cs + Theme"]
end
subgraph "Behaviors & Converters"
Behav["Misc/*Behaviour.cs"]
Conv["Misc/*ValueConverter.cs"]
end
Program --> App
App --> MainWindow
MainWindow --> MainVM
DialogWindow --> MainVM
MainWindow --> Hex
MainWindow --> EditTxt
MainWindow --> TxtKey
MainWindow --> GroupBox
MainWindow --> Behav
MainWindow --> Conv
App --> IDisp
App --> IInv
MainVM --> BaseVM
```
**Diagram sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [GroupBox.cs](file://ClassicAssist.Avalonia/Controls/GroupBox.cs)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvalonEditBehaviour.cs](file://ClassicAssist.Avalonia/Misc/AvalonEditBehaviour.cs)
- [CloseOnClickBehaviour.cs](file://ClassicAssist.Avalonia/Misc/CloseOnClickBehaviour.cs)
- [ComboBoxBehavior.cs](file://ClassicAssist.Avalonia/Misc/ComboBoxBehavior.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [InverseBooleanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [ListBoxAutoScrollBehaviour.cs](file://ClassicAssist.Avalonia/Misc/ListBoxAutoScrollBehaviour.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [PacketEntryBinaryValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryBinaryValueConverter.cs)
- [PacketEntryTextValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryTextValueConverter.cs)
- [StringToResourceConverter.cs](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [WindowInitializedBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowInitializedBehaviour.cs)
- [WindowResizeBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowResizeBehaviour.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.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)
**Section sources**
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [GroupBox.cs](file://ClassicAssist.Avalonia/Controls/GroupBox.cs)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [AvalonEditBehaviour.cs](file://ClassicAssist.Avalonia/Misc/AvalonEditBehaviour.cs)
- [CloseOnClickBehaviour.cs](file://ClassicAssist.Avalonia/Misc/CloseOnClickBehaviour.cs)
- [ComboBoxBehavior.cs](file://ClassicAssist.Avalonia/Misc/ComboBoxBehavior.cs)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [InverseBooleanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [ListBoxAutoScrollBehaviour.cs](file://ClassicAssist.Avalonia/Misc/ListBoxAutoScrollBehaviour.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [PacketEntryBinaryValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryBinaryValueConverter.cs)
- [PacketEntryTextValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryTextValueConverter.cs)
- [StringToResourceConverter.cs](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [WindowInitializedBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowInitializedBehaviour.cs)
- [WindowResizeBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowResizeBehaviour.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.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)
## Core Components
- Application bootstrap and DI setup: The application initializes resources, registers services, and creates the main window.
- Cross-platform dispatching and UI invocation: Abstractions for thread marshaling and UI operations ensure consistent behavior across platforms.
- Custom controls: Specialized controls for hex editing, key input, and text editing with rich UX.
- Behaviors and converters: Declarative enhancements to standard controls and data transformations.
- Window management: Centralized dialog handling and modal workflows.
**Section sources**
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
## Architecture Overview
The UI follows MVVM with Avalonia:
- Views declare layout and bind to ViewModels.
- ViewModels expose state and commands, implementing change notifications.
- Models encapsulate domain data and business rules.
- Cross-platform abstractions isolate platform-specific concerns behind shared interfaces.
```mermaid
classDiagram
class IDispatcher {
+Invoke(action)
+BeginInvoke(action)
}
class IUIInvoker {
+ShowDialog(window, viewModel)
+ShowWindow(window, viewModel)
}
class AvaloniaDispatcher
class AvaloniaUIInvoker
class BaseViewModel {
+NotifyPropertyChanged()
}
class MainWindowViewModel
class MainWindow
class DialogWindow
class DialogWindowViewModel
AvaloniaDispatcher ..|> IDispatcher
AvaloniaUIInvoker ..|> IUIInvoker
MainWindowViewModel --|> BaseViewModel
MainWindow --> MainWindowViewModel : "DataContext"
DialogWindow --> DialogWindowViewModel : "DataContext"
MainWindow --> AvaloniaUIInvoker : "uses"
MainWindow --> AvaloniaDispatcher : "uses"
```
**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)
- [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)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
## Detailed Component Analysis
### MVVM Implementation
- BaseViewModel provides common change notification and property helpers.
- MainWindowViewModel orchestrates UI state and delegates to services via abstractions.
- Views bind to properties and commands; they remain thin and declarative.
```mermaid
sequenceDiagram
participant User as "User"
participant View as "MainWindow"
participant VM as "MainWindowViewModel"
participant Invoker as "AvaloniaUIInvoker"
participant Dialog as "DialogWindow"
User->>View : Click action
View->>VM : Execute command
VM->>Invoker : ShowDialog(dialogVM)
Invoker->>Dialog : Create and show modal
Dialog-->>VM : Result callback
VM-->>View : Update UI state
```
**Diagram sources**
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.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)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
### Cross-Platform UI Abstraction Layer
- IDispatcher and IUIInvoker define contracts for UI threading and window/dialog operations.
- AvaloniaDispatcher implements dispatcher semantics for Avalonia’s UI thread.
- AvaloniaUIInvoker implements cross-platform dialog/window presentation using Avalonia primitives.
```mermaid
flowchart TD
Start(["UI Operation"]) --> CheckThread["Check current thread"]
CheckThread --> IsUIThread{"Is UI thread?"}
IsUIThread --> |Yes| Execute["Execute directly"]
IsUIThread --> |No| Marshal["Marshal to UI thread"]
Marshal --> Execute
Execute --> End(["Done"])
```
**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)
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
### Theme System, Styling, and Resources
- Global styles and themes are defined in XAML resources and merged at app startup.
- Control-specific themes (e.g., GroupBox) provide default look-and-feel.
- Resource dictionaries centralize colors, icons, and reusable styles.
```mermaid
graph LR
AppRes["App.axaml resources"] --> Merged["Merged Dictionaries"]
Merged --> Themes["Themes (Dark/Light)"]
Merged --> Styles["Global Styles"]
Merged --> Icons["Icons & Assets"]
Themes --> Controls["Controls (e.g., GroupBox)"]
Styles --> Controls
Icons --> Controls
```
**Diagram sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
**Section sources**
- [App.axaml](file://ClassicAssist.Avalonia/App.axaml)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
### Custom Controls Library
- HexDumpControl: A specialized control for binary/hex inspection with efficient rendering patterns suitable for large datasets.
- EditTextBlock: An editable text block combining read-only display with inline editing capabilities.
- TextBoxKey: A key-binding capture control for hotkey configuration.
- GroupBox: A themed container control with consistent styling.
```mermaid
classDiagram
class HexDumpControl {
+Data
+Refresh()
}
class EditTextBlock {
+Text
+EditMode(bool)
}
class TextBoxKey {
+KeyBinding
+CaptureKey()
}
class GroupBox {
+Header
}
HexDumpControl <.. EditTextBlock : "used by"
HexDumpControl <.. TextBoxKey : "used by"
GroupBox <.. HexDumpControl : "wraps"
```
**Diagram sources**
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [GroupBox.cs](file://ClassicAssist.Avalonia/Controls/GroupBox.cs)
**Section sources**
- [HexDumpControl.axaml](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [EditTextBlock.axaml](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml)
- [EditTextBlock.axaml.cs](file://ClassicAssist.Avalonia/Controls/EditTextBlock.axaml.cs)
- [TextBoxKey.axaml](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml)
- [TextBoxKey.axaml.cs](file://ClassicAssist.Avalonia/Controls/TextBoxKey.axaml.cs)
- [GroupBox.cs](file://ClassicAssist.Avalonia/Controls/GroupBox.cs)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
### Binding System, Value Converters, and Behaviors
- ValueConverters transform data for display (e.g., DateTime to TimeSpan, lock status, packet entries, string-to-resource lookup).
- Behaviors add interactivity without code-behind (e.g., auto-scroll, close-on-click, combo box behavior, window resize/initialized hooks).
- Bindings connect View properties to ViewModel commands and properties.
```mermaid
flowchart TD
Data["ViewModel Property"] --> Converter["ValueConverter"]
Converter --> ViewProp["View Property"]
Behavior["Behavior"] --> View["View Element"]
Behavior --> Event["Event/Action"]
Event --> Command["Command in ViewModel"]
```
**Diagram sources**
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [InverseBooleanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [PacketEntryBinaryValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryBinaryValueConverter.cs)
- [PacketEntryTextValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryTextValueConverter.cs)
- [StringToResourceConverter.cs](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [AvalonEditBehaviour.cs](file://ClassicAssist.Avalonia/Misc/AvalonEditBehaviour.cs)
- [CloseOnClickBehaviour.cs](file://ClassicAssist.Avalonia/Misc/CloseOnClickBehaviour.cs)
- [ComboBoxBehavior.cs](file://ClassicAssist.Avalonia/Misc/ComboBoxBehavior.cs)
- [ListBoxAutoScrollBehaviour.cs](file://ClassicAssist.Avalonia/Misc/ListBoxAutoScrollBehaviour.cs)
- [WindowInitializedBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowInitializedBehaviour.cs)
- [WindowResizeBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowResizeBehaviour.cs)
**Section sources**
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [InverseBooleanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [PacketEntryBinaryValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryBinaryValueConverter.cs)
- [PacketEntryTextValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryTextValueConverter.cs)
- [StringToResourceConverter.cs](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
- [AvalonEditBehaviour.cs](file://ClassicAssist.Avalonia/Misc/AvalonEditBehaviour.cs)
- [CloseOnClickBehaviour.cs](file://ClassicAssist.Avalonia/Misc/CloseOnClickBehaviour.cs)
- [ComboBoxBehavior.cs](file://ClassicAssist.Avalonia/Misc/ComboBoxBehavior.cs)
- [ListBoxAutoScrollBehaviour.cs](file://ClassicAssist.Avalonia/Misc/ListBoxAutoScrollBehaviour.cs)
- [WindowInitializedBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowInitializedBehaviour.cs)
- [WindowResizeBehaviour.cs](file://ClassicAssist.Avalonia/Misc/WindowResizeBehaviour.cs)
### Window Management and Modal Dialogs
- DialogWindow provides a standardized modal dialog shell.
- DialogWindowViewModel coordinates dialog content and results.
- AvaloniaUIInvoker handles creation and lifetime of dialogs/windows uniformly across platforms.
```mermaid
sequenceDiagram
participant Caller as "Caller ViewModel"
participant Invoker as "AvaloniaUIInvoker"
participant Win as "DialogWindow"
participant VM as "DialogWindowViewModel"
Caller->>Invoker : ShowDialog(VM)
Invoker->>Win : Instantiate and set DataContext
Win->>VM : Initialize and render
VM-->>Caller : Return result on close
```
**Diagram sources**
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [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)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
## Dependency Analysis
- Views depend on ViewModels through DataContext bindings.
- ViewModels depend on shared base classes and abstractions (dispatcher, invoker).
- Custom controls encapsulate complex UI logic and can be reused across views.
- Behaviors and converters are loosely coupled and applied declaratively.
```mermaid
graph TB
Views["Views"] --> VMs["ViewModels"]
VMs --> SharedVM["BaseViewModel"]
VMs --> Abstractions["IDispatcher / IUIInvoker"]
Views --> Controls["Custom Controls"]
Views --> Misc["Behaviors & Converters"]
Controls --> Theming["Theme Resources"]
```
**Diagram sources**
- [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)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
**Section sources**
- [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)
- [HexDumpControl.axaml.cs](file://ClassicAssist.Avalonia/Controls/HexDumpControl.axaml.cs)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
## Performance Considerations
- Virtualization: Prefer virtualizing panels for large lists to reduce memory and improve scroll performance.
- Incremental updates: Batch collection changes and avoid excessive property notifications during bulk operations.
- Efficient rendering: Use custom controls like HexDumpControl optimized for large binary data; avoid heavy per-item visuals.
- Debounced input: For text inputs and key capture, debounce or throttle events to prevent UI thrashing.
- Resource caching: Cache computed values and converter outputs where appropriate to minimize recomputation.
- Responsive design: Use flexible layouts and responsive sizing to adapt to different screen sizes and DPI settings.
[No sources needed since this section provides general guidance]
## Troubleshooting Guide
- Threading issues: Ensure UI updates occur on the UI thread using the dispatcher abstraction.
- Dialog not closing: Verify that dialog results are properly returned and handled by the caller ViewModel.
- Style conflicts: Check resource dictionary merge order and control theme overrides.
- Converter errors: Validate input types and handle nulls gracefully in converters.
- Memory growth: Monitor large collections and enable virtualization; dispose of unused resources.
**Section sources**
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
- [GroupBox.Theme.xaml](file://ClassicAssist.Avalonia/Controls/GroupBox.Theme.xaml)
- [DateTimeToTimeSpanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/DateTimeToTimeSpanValueConverter.cs)
- [InverseBooleanValueConverter.cs](file://ClassicAssist.Avalonia/Misc/InverseBooleanValueConverter.cs)
- [JoinArrayValueConverter.cs](file://ClassicAssist.Avalonia/Misc/JoinArrayValueConverter.cs)
- [LockStatusValueConverter.cs](file://ClassicAssist.Avalonia/Misc/LockStatusValueConverter.cs)
- [PacketEntryBinaryValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryBinaryValueConverter.cs)
- [PacketEntryTextValueConverter.cs](file://ClassicAssist.Avalonia/Misc/PacketEntryTextValueConverter.cs)
- [StringToResourceConverter.cs](file://ClassicAssist.Avalonia/Misc/StringToResourceConverter.cs)
- [HueEntryToRectanglesValueConverter.cs](file://ClassicAssist.Avalonia/Misc/HueEntryToRectanglesValueConverter.cs)
## Conclusion
ClassicAssist.Avalonia implements a clean MVVM architecture with Avalonia UI, providing robust cross-platform abstractions, a comprehensive theming system, reusable custom controls, and a rich set of behaviors and converters. The design emphasizes separation of concerns, testability, and performance, making it suitable for complex desktop applications requiring responsive and maintainable UI layers.