Packet System
Moongate v2 uses concrete packet classes implementing IGameNetworkPacket.
Packet Contract
public interface IGameNetworkPacket
{
byte OpCode { get; }
int Length { get; } // -1 for variable-length
bool TryParse(ReadOnlySpan<byte> data);
void Write(ref SpanWriter writer);
}
Registration Model
Packets are decorated with:
[PacketHandler(0x02, PacketSizing.Fixed, Length = 7, Description = "Move Request")]
Key types:
PacketHandlerAttributeOpCode,Sizing,Length,Description
PacketSizingFixed,Variable
PacketRegistry- metadata + packet factory per opcode
PacketTable.Register(PacketRegistry)- generated registration entrypoint
Runtime Use
NetworkService uses PacketRegistry to:
- resolve descriptor (
TryGetDescriptor) - create packet instance (
TryCreatePacket) - call
TryParse(rawPacket) - publish
IncomingGamePacketto message bus
PacketDispatchService then routes by opcode to registered IPacketListener instances.
Current gameplay examples:
PlayerStatusHandlerlistens toPacketDefinition.GetPlayerStatusPacketBasicStatusrequests enqueuePlayerStatusPacket(0x11)RequestSkillsrequests enqueueSkillListPacket(0x3A)
ItemHandlerlistens to book packetsBookHeaderNewPacket(0xD4) saves writable booktitle/authorBookPagesPacket(0x66) serves page requests and writable page saves
DyeWindowHandlerlistens toDyeWindowPacket(0x95)- the classic dye-tub target flow opens
0x95to the client - the client response on
0x95applies hue to the pending item target
- the classic dye-tub target flow opens
BulletinBoardHandlerlistens toBulletinBoardMessagesPacket(0x71)- double click on a bulletin board opens the classic board window
- client
sub 3/4/5/6requests load messages, post replies, and remove owned leaf messages
Pragmatic POL Coverage Matrix
This matrix tracks the packet subset that is already present in Moongate or still relevant for the current 7.x client target.
Status values:
handler: parsed and wired to gameplay withRegisterPacketHandler(...)outgoing: server-to-client packet emitted by runtime codeparse-only: packet class is registered inPacketRegistry, but no gameplay listener handles it yetmissing: relevant in POL/client docs, but not implemented in Moongate
| Opcode | Op Description | Direction | Moongate Packet Class | Status | Runtime Wiring | Notes |
|---|---|---|---|---|---|---|
0xEF |
Login Seed | C -> S | LoginSeedPacket |
handler |
LoginHandler |
Login bootstrap |
0x80 |
Account Login | C -> S | AccountLoginPacket |
handler |
LoginHandler |
Account auth |
0xA0 |
Server Select | C -> S | ServerSelectPacket |
handler |
LoginHandler |
Shard select |
0x91 |
Game Login | C -> S | GameLoginPacket |
handler |
LoginHandler |
Game-server auth |
0x5D |
Login Character | C -> S | LoginCharacterPacket |
handler |
LoginHandler |
Character enter world |
0xBD |
Client Version | C -> S | ClientVersionPacket |
handler |
LoginHandler |
Stores negotiated client version |
0xF8 |
Character Creation | C -> S | CharacterCreationPacket |
handler |
CharacterHandler |
Modern creation flow |
0x72 |
Request War Mode / War Mode | both | RequestWarModePacket, WarModePacket |
handler + outgoing |
CharacterHandler |
Inbound toggle request and outbound war-mode state reply share opcode 0x72; outgoing packet is intentionally not registry-decorated to avoid direction-agnostic opcode collision |
0x02 |
Move Request | C -> S | MoveRequestPacket |
handler |
MovementHandler |
Core movement |
0x73 |
Ping Message | C -> S | PingMessagePacket |
handler |
PingPongHandler |
Keepalive |
0xC8 |
Client View Range | C -> S | ClientViewRangePacket |
handler |
ClientViewRangeHandler |
View range update |
0x34 |
Get Player Status | C -> S | GetPlayerStatusPacket |
handler |
PlayerStatusHandler |
BasicStatus -> 0x11, RequestSkills -> 0x3A |
0xAD |
Unicode Speech | C -> S | UnicodeSpeechPacket |
handler |
SpeechHandler |
In-game commands and speech |
0xB5 |
Open Chat Window | C -> S | OpenChatWindowPacket |
handler |
ChatHandler |
Opens classic conference chat and creates runtime chat user |
0xB3 |
Chat Text | C -> S | ChatTextPacket |
handler |
ChatHandler |
Conference chat actions (message, join, pm, ignore, ops, voice, kick, whois, emote) |
0x6C |
Target Cursor Commands | C -> S | TargetCursorCommandsPacket |
handler |
PlayerTargetService |
Target callbacks |
0xBF |
General Information | C -> S | GeneralInformationPacket |
handler |
GeneralInformationHandler |
Includes context menu / stat lock subcommands |
0xD6 |
Mega Cliloc | C -> S | MegaClilocPacket |
handler |
ToolTipHandler |
Tooltip requests |
0xB1 |
Gump Menu Selection | C -> S | GumpMenuSelectionPacket |
handler |
GumpHandler |
Gump button replies |
0x06 |
Double Click | C -> S | DoubleClickPacket |
handler |
ItemHandler |
Item use / open flows |
0x09 |
Single Click | C -> S | SingleClickPacket |
handler |
ItemHandler |
Labels / tooltip-side behavior |
0x07 |
Pick Up Item | C -> S | PickUpItemPacket |
handler |
ItemHandler |
Drag start |
0x08 |
Drop Item | C -> S | DropItemPacket |
handler |
ItemHandler |
Container / world drop |
0x13 |
Drop -> Wear Item | C -> S | DropWearItemPacket |
handler |
ItemHandler |
Equip flow |
0x66 |
Books (Pages) | C -> S | BookPagesPacket |
handler |
ItemHandler |
Page request and writable page save |
0x71 |
Bulletin Board Messages | both | BulletinBoardMessagesPacket, BulletinBoardDisplayPacket, BulletinBoardSummaryPacket, BulletinBoardMessagePacket |
handler + outgoing |
BulletinBoardHandler, BulletinBoardModule / BulletinBoardService |
Classic bulletin board open/read/post/remove flow |
0x95 |
Dye Window | both | DyeWindowPacket, DisplayDyeWindowPacket |
handler + outgoing |
DyeWindowHandler, DyeModule / DyeColorService |
Classic dye tub hue picker flow; outgoing packet intentionally not registry-decorated to avoid opcode collision |
0xD4 |
Book Header (New) | C -> S | BookHeaderNewPacket |
handler |
ItemHandler |
Writable title / author save |
0xD9 |
Spy On Client | C -> S | SpyOnClientPacket |
handler |
PlayerHandler |
Minimal session-side handling |
0x03 |
Talk Request | C -> S | TalkRequestPacket |
parse-only |
none | Legacy speech path not wired |
0x12 |
Request Skill / Use | C -> S | RequestSkillUsePacket |
parse-only |
none | Skill-use flow still missing |
0x83 |
Delete Character | C -> S | DeleteCharacterPacket |
parse-only |
none | No delete flow wired |
0xA8 |
Server List | S -> C | ServerListPacket |
outgoing |
LoginHandler |
Shard list |
0x8C |
Server Redirect | S -> C | ServerRedirectPacket |
outgoing |
LoginHandler |
Redirect to game server |
0x1B |
Login Confirm | S -> C | LoginConfirmPacket |
outgoing |
login flow | Character accepted |
0xA9 |
Characters / Starting Locations | S -> C | CharactersStartingLocationsPacket |
outgoing |
login flow | Character list + starts |
0xB9 |
Support Features | S -> C | SupportFeaturesPacket |
outgoing |
login flow | Enables client features |
0x55 |
Login Complete | S -> C | LoginCompletePacket |
outgoing |
login flow | Enter world complete |
0x22 |
Move Confirm | S -> C | MoveConfirmPacket |
outgoing |
movement flow | Movement ack |
0x21 |
Move Deny | S -> C | MoveDenyPacket |
outgoing |
movement flow | Movement reject |
0x78 |
Mobile Incoming | S -> C | MobileIncomingPacket |
outgoing |
world/entity sync | Nearby mobiles |
0x20 |
Draw Player | S -> C | DrawPlayerPacket |
outgoing |
login/move flow | Draw controlled mobile |
0x2E |
Worn Item | S -> C | WornItemPacket |
outgoing |
equipment sync | Equipped visuals |
0x24 |
Draw Container | S -> C | DrawContainerPacket |
outgoing |
container flow | Open container |
0x3C |
Add Multiple Items To Container | S -> C | AddMultipleItemsToContainerPacket |
outgoing |
container flow | Batched contents |
0x88 |
Paperdoll | S -> C | PaperdollPacket |
outgoing |
character UI | Paperdoll open |
0x11 |
Status Bar Info | S -> C | PlayerStatusPacket |
outgoing |
PlayerStatusHandler |
Modern 7.x status payload |
0xB2 |
Chat Command | S -> C | ChatCommandPacket |
outgoing |
ChatSystemService |
Classic conference chat responses and UI updates |
0x3A |
Send Skills | S -> C | SkillListPacket |
outgoing |
PlayerStatusHandler |
Full skill list with lock state |
0x23 |
Dragging Of Item | S -> C | DraggingOfItemPacket |
outgoing |
item drag flow | Drag visual |
0xAE |
Unicode Speech Message | S -> C | UnicodeSpeechMessagePacket |
outgoing |
speech/system messages | Server speech |
0xB0 |
Generic Gump | S -> C | GenericGumpPacket |
outgoing |
gump flow | Standard gump |
0xDD |
Compressed Gump | S -> C | CompressedGumpPacket |
outgoing |
gump flow | Compressed gump |
0xF3 |
Object Information | S -> C | ObjectInformationPacket |
outgoing |
item/world sync | Item/object updates |
0x76 |
Server Change | S -> C | ServerChangePacket |
outgoing |
map transition flow | Map/server boundary change |
0x65 |
Weather | S -> C | SetWeatherPacket |
outgoing |
world presentation | Client 7.x still supports it |
0x54 |
Play Sound Effect | S -> C | PlaySoundEffectPacket |
outgoing |
world presentation | Audio cue |
0x70 |
Graphical Effect | S -> C | GraphicalEffectPacket |
outgoing |
world presentation | Classic effect |
0xC0 |
Hued Effect | S -> C | HuedEffectPacket |
outgoing |
world presentation | Colored effect |
0xC7 |
Particle Effect | S -> C | ParticleEffectPacket |
outgoing |
world presentation | Particle effect |
0x7C |
Relay | both | none | missing |
none | Relevant in POL docs, not implemented in Moongate |
0x16 |
Status Bar Info (old) | S -> C | none | missing |
none | POL legacy status packet; Moongate uses modern 0x11 only |
0x39 |
Group Remove / old chat | C -> S | none | missing |
none | Not targeted for current client/runtime |
Serialization
Outbound packets are serialized with SpanWriter in OutboundPacketSender.
- fixed packets typically pre-size buffer with
Length - variable packets can use dynamic writer growth
- packet logging can output hex dump when
LogPacketDatais enabled
Current notable outgoing packet classes:
PlayerStatusPacket- modern
7.xstatus layout - reads effective mobile state from
UOMobileEntity
- modern
SkillListPacket- outgoing
0x3A - serializes the persisted mobile skill table in skill-id order
- includes lock state, but not per-skill caps
- outgoing
BookHeaderNewPacket- opens the classic book UI
- toggles client writable mode per item
Source Generation
Moongate.Generators provides generated packet artifacts used by runtime:
- packet table registration code
- packet opcode constants (
PacketDefinitionpartial)
This avoids manual opcode duplication and keeps registration centralized.
Listener Registration Generation
Server listener wiring is also source-generated.
Listener classes declare handled opcodes:
[RegisterPacketHandler(PacketDefinition.MoveRequestPacket)]
public class MovementHandler : BasePacketListener
{
// ...
}
Moongate.Generators produces bootstrap code that calls
RegisterPacketHandler<TListener>(container, opCode) for all discovered attributes.
This keeps:
- listener mapping explicit and compile-time validated.
- bootstrap code shorter and easier to maintain.
- runtime startup free from reflection-based handler scanning.
Game Event Listener Registration Generation
In addition to packet handler registration, Moongate also generates game-event listener subscriptions.
Listener classes decorated with [RegisterGameEventListener] are scanned at compile time.
For each implemented IGameEventListener<TEvent>, generated bootstrap code subscribes the listener on IGameEventBusService.
Previous: Protocol Reference