first commit
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user