487 lines
23 KiB
Markdown
487 lines
23 KiB
Markdown
# 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] |