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,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.