acdream/docs/research/deepdives/r08-network-protocol-atlas.md
Erik 3f913f1999 docs+feat: 13 retail-AC deep-dives (R1-R13) + C# port scaffolds + roadmap E-H
78,000 words of grounded, citation-backed research across 13 major AC
subsystems, produced by 13 parallel Opus-4.7 high-effort agents. Plus
compact C# port scaffolds for the top-5 systems and a phase-E-through-H
roadmap update sequencing the work.

Research (docs/research/deepdives/):
- 00-master-synthesis.md          (navigation hub + dependency graph)
- r01-spell-system.md        5.4K words (fizzle sigmoid, 8 tabs, 0x004A wire)
- r02-combat-system.md       5.9K words (damage formula, crit, body table)
- r03-motion-animation.md    8.2K words (450+ commands, 27 hook types)
- r04-vfx-particles.md       5.8K words (13 ParticleType, PhysicsScript)
- r05-audio-sound.md         5.6K words (DirectSound 8, CPU falloff)
- r06-items-inventory.md     7.4K words (ItemType flags, EquipMask 31 slots)
- r07-character-creation.md  6.3K words (CharGen dat, 13 heritages)
- r08-network-protocol-atlas 9.7K words (63+149+94 opcodes mapped)
- r09-dungeon-portal-space.md 6.3K words (EnvCell, PlayerTeleport flow)
- r10-quest-dialogs.md       7.1K words (emote-script VM, 122 actions)
- r11-allegiance.md          5.4K words (tree + XP passup + 5 channels)
- r12-weather-daynight.md    4.5K words (deterministic client-side)
- r13-dynamic-lighting.md    4.9K words (8-light cap, hard Range cutoff)

Every claim cites a FUN_ address, ACE file path, DatReaderWriter type,
or holtburger/ACViewer reference. The master synthesis ties them into a
dependency graph and phase sequence.

Key architectural finding: of 94 GameEvents in the 0xF7B0 envelope,
ZERO are handled today — that's the largest network-protocol gap and
blocks F.2 (items) + F.5 (panels) + H.1 (chat).

C# scaffolds (src/AcDream.Core/):
- Items/ItemInstance.cs    — ItemType/EquipMask enums, ItemInstance,
                             Container, PropertyBundle, BurdenMath
- Spells/SpellModel.cs      — SpellDatEntry, SpellComponentEntry,
                             SpellCastStateMachine, ActiveBuff,
                             SpellMath (fizzle sigmoid + mana cost)
- Combat/CombatModel.cs     — CombatMode/AttackType/DamageType/BodyPart,
                             DamageEvent record, CombatMath (hit-chance
                             sigmoids, power/accuracy mods, damage formula),
                             ArmorBuild
- Audio/AudioModel.cs       — SoundId enum, SoundEntry, WaveData,
                             IAudioEngine / ISoundCache contracts,
                             AudioFalloff (inverse-square)
- Vfx/VfxModel.cs           — 13 ParticleType integrators, EmitterDesc,
                             PhysicsScript + hooks, Particle struct,
                             ParticleEmitter, IParticleSystem contract

All Core-layer data models; platform-backed engines live in AcDream.App.
Compiles clean; 470 tests still pass.

Roadmap (docs/plans/2026-04-11-roadmap.md):
- Phase E — "Feel alive": motion-hooks + audio + VFX
- Phase F — Fight + cast + gear: GameEvent dispatch, inventory,
            combat, spell, core panels
- Phase G — World systems: sky/weather, dynamic lighting, dungeons
- Phase H — Social + progression: chat, allegiance, quests, char creation
- Phase J — Long-tail (renumbered from old Phase E)

Quick-lookup table updated with 10+ new rows mapping observations to
new phase letters.
2026-04-18 10:32:44 +02:00

58 KiB
Raw Permalink Blame History

R8 — Network Protocol Atlas

Scope: exhaustive map of every AC retail network opcode the client must see, send, or at least tolerate. This document is the single reference for every port ticket under phases C, D, E (chat), and F (inventory/combat/ spells). If an opcode is listed here as "unhandled," we already know what it is and what it needs — the only remaining work is wiring up the parser

  • event surface.

Inputs cross-referenced:

  • references/ACE/Source/ACE.Server/Network/GameMessages/GameMessageOpcode.cs — canonical S2C primary-opcode enum.
  • references/ACE/Source/ACE.Server/Network/GameAction/GameActionType.cs — canonical C2S GameAction sub-opcode enum.
  • references/ACE/Source/ACE.Server/Network/GameEvent/GameEventType.cs — canonical S2C GameEvent sub-opcode enum.
  • references/ACE/Source/ACE.Server/Network/Handlers/*.cs — handler implementations (what the server accepts, what fields it expects).
  • references/Chorizite.ACProtocol/Chorizite.ACProtocol/protocol.xml — the authoritative XML generated from decompiled client stubs.
  • references/holtburger/crates/holtburger-protocol/src/opcodes.rs — curated "what a real client actually sends / listens for" list, 829 lines, with cross-validated comments.
  • docs/research/decompiled/chunk_006B0000.c (confirmed 0xF7B0 switch).
  • src/AcDream.Core.Net/ — what acdream handles today.

How to read the tables:

  • "Dir": C→S (client to server), S→C (server to client), or bi (can travel either direction — rare; mostly DDD and TurbineChat).
  • "Envelope": GM = standalone GameMessage (primary opcode at the top of the body), GA = client-to-server GameAction inside the 0xF7B1 envelope, GE = server-to-client GameEvent inside the 0xF7B0 envelope. Login- phase opcodes use neither envelope (they ride on header flags).
  • "Status": done = full parse/dispatch + event surface in acdream today; partial = parsed but not exposed as an event, or built but not generated by player input; stub = recognised opcode but body is ignored; unhandled = acdream does not parse this opcode at all today.
  • "Prio": rank for minimum viable play. P0 blocks login. P1 blocks basic in-world feedback (chat, health, combat). P2 blocks inventory/ spells. P3 is housing, allegiance, fellowship. P4 is admin, minigames, barber.

1. Transport layer — recap

AC's wire stack is a three-layer stack on top of UDP:

UDP datagram
 ├─ 20-byte PacketHeader             src/AcDream.Core.Net/Packets/PacketHeader.cs
 ├─ N×MessageFragment                  (0..many, depending on header.Flags)
 │   ├─ 16-byte MessageFragmentHeader  src/AcDream.Core.Net/Packets/MessageFragmentHeader.cs
 │   └─ fragment payload               (≤448 bytes)
 └─ optional retransmit body (if Retransmission flag set)

1.1 PacketHeader (20 bytes, LE)

Off Name Type Notes
0 Sequence u32 Monotonic per direction. 0 = control/handshake packets.
4 Flags u32 PacketHeaderFlags bitmask (see below).
8 Checksum u32 Hash32 of header+body with this field replaced by 0xBADD70DD. When EncryptedChecksum flag is set, XOR with one 32-bit word of ISAAC keystream before transmit.
12 Id u16 Session id, assigned in ConnectRequest by the server.
14 Time u16 Server-time echo for latency tracking. Clients may send 0.
16 DataSize u16 Total body size (excludes this 20-byte header).
18 Iteration u16 Retransmit iteration counter.

1.2 PacketHeaderFlags (32-bit bitmask, wire source of truth)

Value Name Meaning
0x00000001 Retransmission Body starts with one u32 retransmit-sequence, then the original body.
0x00000002 EncryptedChecksum The Checksum field has been XOR'd with the next ISAAC keystream word.
0x00000004 BlobFragments Body contains one or more MessageFragment blocks.
0x00000100 ServerSwitch Optional body prefix: u32 ServerSwitchType (0=World, 1=Logon).
0x00000200 LogonServerAddr Body prefix: a sockaddr blob (u16 family, u16 port, u32 IPv4, 8 bytes padding).
0x00000400 EmptyHeader1 Observed rarely; legacy.
0x00000800 Referral Body prefix: u64 cookie steering the client to another server.
0x00001000 RequestRetransmit Body: u32 count + count×u32 sequences to retransmit.
0x00002000 RejectRetransmit Body: u32 count + count×u32 rejected sequences.
0x00004000 AckSequence Body: u32 highest-sequence-received.
0x00008000 Disconnect No body; teardown.
0x00010000 LoginRequest Body is the LoginRequest blob.
0x00020000 WorldLoginRequest (unused today, pre-live legacy.)
0x00040000 ConnectRequest Body: double serverTime, u64 cookie, u32 clientId, u32 serverSeed, u32 clientSeed, u32 padding.
0x00080000 ConnectResponse Body: u64 cookie (echo).
0x00100000 NetError Body: u32 errorCode.
0x00200000 NetErrorDisconnect Body: u32 errorCode, u32 reason + disconnect.
0x00400000 CICMDCommand Legacy admin control channel.
0x01000000 TimeSync Body: double clientTime.
0x02000000 EchoRequest Body: float clientTime.
0x04000000 EchoResponse Body: float clientTime, float serverTime.
0x08000000 Flow Body: u32 bytesSinceLast, u16 delta, u16 pad — TCP-style flow control.

1.3 MessageFragmentHeader (16 bytes, LE)

Off Name Type Notes
0 Sequence u32 Per-message sequence. Outbound messages set the high bit (0x80000000).
4 Id u32 Logical message id — fragments with the same Id belong to the same logical GameMessage.
8 Count u16 Total fragments in this logical message.
10 TotalSize u16 Total bytes of this fragment including the 16-byte header. Max 464.
12 Index u16 0-based index of this fragment in the logical message.
14 Queue u16 GameMessageGroupEvent=1, Control=2, Weenie=3, Logon=4, Database=5, UIQueue=9, SmartBox=10, etc.

1.4 ISAAC encryption

Each direction has its own IsaacRandom (ported in Cryptography/), seeded from the 4-byte server seed (for the inbound stream) and 4-byte client seed (for the outbound stream) that the server returns in the ConnectRequest handshake. Every packet with EncryptedChecksum set XORs the header Checksum field with the next u32 drawn from that direction's ISAAC keystream. Cleartext control packets (ACKs, login, connect response, disconnect) do NOT advance ISAAC.

1.5 Ack protocol (source: holtburger session/receive.rs)

Every received server packet whose Sequence > 0 and that does NOT already carry the AckSequence flag gets exactly one ack queued back. This is the "eager ack" pattern — there is no periodic ack timer in the retail client. The ack packet is:

PacketHeader {
  Sequence = last client sequence sent (no increment),
  Flags    = AckSequence,
  Id       = session id,
}
body = u32 server_sequence_being_acked   // cleartext — no ISAAC

Failing to ack → ACE emits "Network Timeout" after ~60s. Symptom visible to other clients: character appears as a stationary purple loading haze.

1.6 Sequence counters (four flavours, movement-only)

Separate from the packet-level Sequence, a player carries four u16 sequence counters that the server uses to detect stale/out-of-order movement messages. These live on WorldSession as _instanceSequence, _teleportSequence, _serverControlSequence, _forcePositionSequence. They're seeded from the player's own CreateObject and updated whenever an inbound UpdatePosition or PlayerTeleport arrives. Every outbound MoveToState / AutonomousPosition must echo them or ACE silently rejects the message.


2. GameMessage opcodes (S→C primary)

These ride as standalone messages — the first u32 of the fragment body is the opcode itself, followed immediately by the payload.

Hex Name Envelope Dir Status Prio Notes
0x0024 InventoryRemoveObject GM S→C unhandled P2 u32 guid — client-side inventory eviction.
0x0197 SetStackSize GM S→C unhandled P2 u32 guid, u32 newStackSize.
0x019E PlayerKilled GM S→C unhandled P1 u32 victimGuid, u32 killerGuid, string message. Triggers the dead-player state.
0x01E0 EmoteText GM S→C unhandled P1 string message — "The Olthoi growls at you." class feedback.
0x01E2 SoulEmote GM S→C unhandled P3 u32 senderGuid, u32 motion, string text.
0x02BB HearSpeech GM S→C unhandled P1 string16L text, string16L sender, u32 senderGuid, u32 chatType. Local-area speech.
0x02BC HearRangedSpeech GM S→C unhandled P1 Same layout as HearSpeech but longer radius (shouts).
0x02CD PrivateUpdatePropertyInt GM S→C unhandled P1 u32 guid, u32 propertyId, u32 value — Only sent to the object's owner.
0x02CE PublicUpdatePropertyInt GM S→C unhandled P1 Same as above; sent to everyone who sees the object.
0x02CF / 0x02D0 Private/PublicUpdatePropertyInt64 GM S→C unhandled P1 u32 guid, u32 propId, u64 value.
0x02D1 / 0x02D2 Private/PublicUpdatePropertyBool GM S→C unhandled P1 u32 guid, u32 propId, u32 value.
0x02D3 / 0x02D4 Private/PublicUpdatePropertyFloat GM S→C unhandled P1 u32 guid, u32 propId, f64 value.
0x02D5 / 0x02D6 Private/PublicUpdatePropertyString GM S→C unhandled P1 u32 guid, u32 propId, string16L value.
0x02D7 / 0x02D8 Private/PublicUpdatePropertyDataID GM S→C unhandled P2 u32 guid, u32 propId, u32 dataId.
0x02D9 / 0x02DA Private/PublicUpdatePropertyInstanceID GM S→C unhandled P2 u32 guid, u32 propId, u32 iid.
0x02DB / 0x02DC Private/PublicUpdatePosition GM S→C unhandled P2 u32 guid, u32 propId, PositionPack.
0x02DD / 0x02DE Private/PublicUpdateSkill GM S→C unhandled P2 u32 guid, u32 skillId, SkillValue.
0x02DF / 0x02E0 Private/PublicUpdateSkillLevel GM S→C unhandled P2 Skill-level only.
0x02E3 / 0x02E4 Private/PublicUpdateAttribute GM S→C unhandled P1 Strength/Endurance/etc.
0x02E7 / 0x02E8 Private/PublicUpdateVital GM S→C unhandled P1 Max HP/Stam/Mana + regen.
0x02E9 PrivateUpdateAttribute2ndLevel GM S→C unhandled P1 Current vital value (the fast-tick channel).
0xEA60 AdminEnvirons GM S→C unhandled P4 Admin-tool overlay.
0xF619 PositionAndMovement GM S→C unhandled P4 Ghost opcode — declared but never fired by ACE.
0xF625 ObjDescEvent GM S→C unhandled P1 u32 guid, ObjectDescription — full re-send of visual description (body parts, textures, palettes). Critical for seeing other players' gear changes.
0xF643 CharacterCreateResponse / CharacterRestoreResponse GM S→C unhandled P0+ u32 responseCode — login-phase, only relevant after char-create. Same opcode, two semantics (disambiguated by session state).
0xF653 CharacterLogOff GM bi partial P0 No payload. Client sends before Disconnect to release the character lock immediately. acdream sends it from Dispose.
0xF655 CharacterDelete GM bi unhandled P4 u32 slot — char-select-screen deletion.
0xF656 CharacterCreate GM C→S unhandled P4 Full character-creation blob — heritage, gender, starting town, appearance.
0xF657 CharacterEnterWorld GM C→S done P0 u32 characterGuid, string16L account. Built by Messages/CharacterEnterWorld.cs.
0xF658 CharacterList GM S→C done P0 u32 serverName?, u32 numChars, char[] chars, u32 accountSlots, u32 accountGuid. Parsed in Messages/CharacterList.cs.
0xF659 CharacterError GM S→C unhandled P0 u32 errorCode — login failure enum. We should parse this to give the user a real error instead of a timeout.
0xF6EA ForceObjectDescSend GM bi unhandled P2 u32 guid. Both directions use the same opcode; C→S asks the server to re-send, S→C pushes a forced refresh.
0xF745 CreateObject GM S→C done P0 Parser: Messages/CreateObject.cs (538 lines). Layout: u32 guid, WeenieHeader, ObjectDescription, PhysicsData. Emits EntitySpawned event.
0xF746 PlayerCreate GM S→C partial P0 Identifies our own character guid. acdream watches for this to send LoginComplete. Does NOT parse the body (it's a full CreateObject-shaped payload — we rely on 0xF745 for that to arrive separately, though retail bundles both).
0xF747 ObjectDelete GM S→C unhandled P1 u32 guid, u16 instanceSequence. When an object leaves our bubble or is destroyed. Without handling this, stale entities accumulate forever.
0xF748 UpdatePosition GM S→C done P0 Parser: Messages/UpdatePosition.cs. Emits PositionUpdated event.
0xF749 ParentEvent GM S→C unhandled P1 u32 parentGuid, u32 childGuid, u32 equipLocation, u32 placementId — item equipped / child attached. Needed to draw weapons in hands, clothing over armour.
0xF74A PickupEvent GM S→C unhandled P2 u32 guid, u32 animationType — player picks up an item, animation dispatched.
0xF74B SetState GM S→C unhandled P1 u32 guid, u32 physicsState, u16 instanceSeq, u16 stateSeq — door opens, chest unlocks, visibility flips.
0xF74C UpdateMotion / MovementEvent GM S→C done P0 Parser: Messages/UpdateMotion.cs. Emits MotionUpdated event. Two names are the same opcode — ACE aliases.
0xF74E VectorUpdate GM S→C unhandled P1 u32 guid, f32 vx, f32 vy, f32 vz, f32 avx, f32 avy, f32 avz, u16 seq, u16 pad — velocity + angular velocity. Missile tracking, continuous turns.
0xF750 Sound GM S→C unhandled P2 u32 guid, u32 soundId, f32 volume — spatialised SFX trigger.
0xF751 PlayerTeleport GM S→C done P0 Parser inline in WorldSession.cs. Emits TeleportStarted with u16 teleportSequence.
0xF752 AutonomyLevel GM S→C unhandled P1 u32 autonomyLevel — server tells client how much physics trust to grant. Default 0 = full client sim; higher = server authoritative.
0xF753 AutonomousPosition GM S→C unhandled P1 Server-forced position resync. Same body as C→S AutonomousPosition (see §3). Causes a snap.
0xF754 PlayScriptId GM S→C unhandled P2 u32 guid, u32 scriptId — trigger a pre-compiled script effect.
0xF755 PlayEffect / PlayScriptType GM S→C unhandled P2 u32 guid, u32 effectType, f32 scale — particle/visual overlay.
0xF7B0 GameEvent GM S→C unhandled P1 The container for every "ordered" server event. Sub-opcode table in §4.
0xF7B1 GameAction GM C→S done (partial) P0 acdream builds LoginComplete, MoveToState, AutonomousPosition, Jump. Sub-opcode table in §3.
0xF7C1 AccountBanned GM S→C unhandled P4 u32 bannedUntilUnixTime, string16L reason.
0xF7C8 CharacterEnterWorldRequest GM C→S done P0 Built by Messages/CharacterEnterWorld.cs::BuildEnterWorldRequestBody. No payload.
0xF7C9 JumpNonAutonomous GM bi unhandled P4 Server-side legacy jump; not sent by live ACE.
0xF7CA ReceiveAccountData GM S→C unhandled P4 Admin inspection.
0xF7CB ReceivePlayerData GM S→C unhandled P4 Admin inspection.
0xF7CC GetServerVersion GM C→S unhandled P4 Admin-only.
0xF7CD FriendsOld GM C→S unhandled P4 Obsolete.
0xF7D9 CharacterRestore GM C→S unhandled P4 Restore a deleted character within grace period.
0xF7DB UpdateObject GM S→C unhandled P1 Heavy update — re-serializes the complete WorldObject. Used on gear swaps, morphs, level-ups.
0xF7DC AccountBoot / AccountBooted GM S→C unhandled P1 string16L reason — server-initiated kick. Should transition to Failed state.
0xF7DE TurbineChat GM bi unhandled P1 Turbine's social chat (General/Trade/LFG/Allegiance/Society). Complex nested blob, see §7.4.
0xF7DF CharacterEnterWorldServerReady GM S→C done P0 No payload. acdream awaits it in EnterWorld as an ack that the server got our request.
0xF7E0 ServerMessage / TextboxString GM S→C unhandled P1 string16L text, u32 chatType. System chat line in the main log.
0xF7E1 ServerName / WorldInfo GM S→C unhandled P0 u32 currentConnections, u32 maxConnections, string16L serverName. Displayed on char-select.
0xF7E2 DDD_DataMessage GM bi unhandled P4 Patch-stream file chunk — only triggers when dat versions mismatch.
0xF7E3 DDD_RequestDataMessage GM C→S unhandled P4 u32 fileType, u32 fileId — client asks for a file.
0xF7E4 DDD_ErrorMessage GM S→C unhandled P4 u32 fileType, u32 fileId, u32 errorCode.
0xF7E5 DDD_Interrogation GM S→C done P0 No payload beyond opcode. Server asks "what dat versions do you have?"
0xF7E6 DDD_InterrogationResponse GM C→S done P0 Built by Messages/DddInterrogationResponse.cs — reports language=1 English, zero known lists.
0xF7E7 DDD_BeginDDD GM S→C unhandled P4 Server tells client patching will begin; u32 totalIterations, u64 totalBytes, ....
0xF7E8 DDD_BeginPullDDD GM S→C unhandled P4 Alternative patch entry.
0xF7E9 DDD_IterationData GM S→C unhandled P4 One iteration record during patching.
0xF7EA DDD_EndDDD GM bi unhandled P4 Patching finished / client acknowledges.

Total primary S→C opcodes: 63. Currently handled by acdream: 7 (CharacterList, CharacterEnterWorldServerReady, CreateObject, UpdateMotion, UpdatePosition, PlayerTeleport, DDD_Interrogation) plus the PlayerCreate trigger. Unhandled: 56 — many of them property updates that share a single parser.


3. GameAction sub-opcodes (C→S, inside 0xF7B1 envelope)

Wire layout of every GameAction on the outbound side:

u32 0xF7B1                          // GameMessage opcode (GameAction envelope)
u32 sequence                        // monotonic per-session action counter
u32 actionType                      // one of the values below
<payload bytes>                     // variable

ACE's GameActionPacket.HandleGameAction reads the sequence field and ignores its value (// TODO: verify sequence in the source), but live clients still increment it — acdream does too via WorldSession.NextGameActionSequence().

Hex Name Dir Status Prio Payload
0x0005 SetSingleCharacterOption C→S unhandled P3 u32 optionKey, u32 value. Appear-offline, show-cloak, etc.
0x0008 TargetedMeleeAttack C→S unhandled P1 u32 targetGuid, u32 attackHeight, f32 powerLevel.
0x000A TargetedMissileAttack C→S unhandled P2 u32 targetGuid, u32 attackHeight, f32 accuracyLevel.
0x000F SetAfkMode C→S unhandled P3 u32 enabled.
0x0010 SetAfkMessage C→S unhandled P3 string16L message.
0x0015 Talk C→S unhandled P1 string16L message — local-area chat.
0x0017 RemoveFriend C→S unhandled P3 u32 guid.
0x0018 AddFriend C→S unhandled P3 string16L name.
0x0019 PutItemInContainer C→S unhandled P2 u32 itemGuid, u32 containerGuid, u32 placement.
0x001A GetAndWieldItem C→S unhandled P2 u32 itemGuid, u32 equipLocation.
0x001B DropItem C→S unhandled P2 u32 itemGuid.
0x001D SwearAllegiance C→S unhandled P3 u32 patronGuid.
0x001E BreakAllegiance C→S unhandled P3 u32 otherGuid.
0x001F AllegianceUpdateRequest C→S unhandled P3 u32 onOff.
0x0025 RemoveAllFriends C→S unhandled P3
0x0026 TeleToPklArena C→S unhandled P3
0x0027 TeleToPkArena C→S unhandled P3
0x002C TitleSet C→S unhandled P3 u32 titleId.
0x0030 QueryAllegianceName C→S unhandled P3
0x0031 ClearAllegianceName C→S unhandled P3
0x0032 TalkDirect C→S unhandled P1 string16L target, string16L message — whisper by location/target.
0x0033 SetAllegianceName C→S unhandled P3 string16L name.
0x0035 UseWithTarget C→S unhandled P2 u32 sourceGuid, u32 targetGuid.
0x0036 Use C→S unhandled P2 u32 guid — click a door, Lifestone, portal, corpse, etc.
0x003B0x0042 Allegiance officer/chat/house C→S unhandled P3 Various allegiance admin ops.
0x0044 RaiseVital C→S unhandled P2 u32 vital, u64 xpSpent.
0x0045 RaiseAttribute C→S unhandled P2 u32 attr, u64 xpSpent.
0x0046 RaiseSkill C→S unhandled P2 u32 skillId, u64 xpSpent.
0x0047 TrainSkill C→S unhandled P2 u32 skillId, u32 credits.
0x0048 CastUntargetedSpell C→S unhandled P2 u32 spellId.
0x004A CastTargetedSpell C→S unhandled P2 u32 targetGuid, u32 spellId.
0x0053 ChangeCombatMode C→S unhandled P1 u32 combatMode — Peace/Melee/Missile/Magic.
0x0054 StackableMerge C→S unhandled P2 u32 mergeFromGuid, u32 mergeToGuid, u32 amount.
0x0055 StackableSplitToContainer C→S unhandled P2 u32 stackGuid, u32 containerGuid, u32 placement, u32 amount.
0x0056 StackableSplitTo3D C→S unhandled P2 u32 stackGuid, u32 amount.
0x0058 ModifyCharacterSquelch C→S unhandled P3 u32 guid, u32 squelchType, bool add.
0x0059 ModifyAccountSquelch C→S unhandled P3 string16L account, u32 squelchType, bool add.
0x005B ModifyGlobalSquelch C→S unhandled P3 u32 channelId, bool enable.
0x005D Tell C→S unhandled P1 string16L targetName, string16L message — whisper by name.
0x005F Buy C→S unhandled P2 u32 vendorGuid, u32 count, ItemProfile[count].
0x0060 Sell C→S unhandled P2 Same shape.
0x0063 TeleToLifestone C→S unhandled P2
0x00A1 LoginComplete C→S done P0 No payload. Built by Messages/GameActionLoginComplete.cs.
0x00A2 FellowshipCreate C→S unhandled P3 string16L name, bool openness, bool shareXP.
0x00A3 FellowshipQuit C→S unhandled P3 bool disband.
0x00A4 FellowshipDismiss C→S unhandled P3 u32 guid.
0x00A5 FellowshipRecruit C→S unhandled P3 u32 guid.
0x00A6 FellowshipUpdateRequest C→S unhandled P3 bool open.
0x00AA0x00AE Book* C→S unhandled P4 Book add/modify/delete/query pages.
0x00BF SetInscription C→S unhandled P3 u32 itemGuid, string16L text.
0x00C8 IdentifyObject C→S unhandled P1 u32 guid. Assess target; server replies with 0xF7B0/0x00C9.
0x00CD GiveObjectRequest C→S unhandled P2 u32 targetGuid, u32 itemGuid, u32 amount.
0x00D6 AdvocateTeleport C→S unhandled P4 Admin.
0x0140 AbuseLogRequest C→S unhandled P4
0x0145 AddChannel C→S unhandled P3 string16L channelName.
0x0146 RemoveChannel C→S unhandled P3 string16L channelName.
0x0147 ChatChannel C→S unhandled P1 u32 channelId, string16L message.
0x0148 ListChannels C→S unhandled P3
0x0149 IndexChannels C→S unhandled P3
0x0195 NoLongerViewingContents C→S unhandled P2 u32 containerGuid.
0x019B StackableSplitToWield C→S unhandled P2 u32 stackGuid, u32 equipLocation, u32 amount.
0x019C AddShortCut C→S unhandled P3 u32 slot, u32 objectType, u32 targetId.
0x019D RemoveShortCut C→S unhandled P3 u32 slot.
0x01A1 SetCharacterOptions C→S unhandled P3 Client option bitmap.
0x01A8 RemoveSpellC2S C→S unhandled P2 u32 spellId.
0x01B7 CancelAttack C→S unhandled P1
0x01BF QueryHealth C→S unhandled P1 u32 guid. Server replies with GameEvent UpdateHealth (0x01C0).
0x01C2 QueryAge C→S unhandled P4
0x01C4 QueryBirth C→S unhandled P4
0x01DF Emote C→S unhandled P2 string16L emote.
0x01E1 SoulEmote C→S unhandled P3 string16L emote.
0x01E3 AddSpellFavorite C→S unhandled P3 u32 spellId, u32 bar, u32 slot.
0x01E4 RemoveSpellFavorite C→S unhandled P3 u32 bar, u32 slot.
0x01E9 PingRequest C→S unhandled P1 u32 clientId. Server replies with 0xF7B0/0x01EA. Double-duty keepalive.
0x01F6 OpenTradeNegotiations C→S unhandled P3 u32 targetGuid.
0x01F7 CloseTradeNegotiations C→S unhandled P3
0x01F8 AddToTrade C→S unhandled P3 u32 itemGuid, u32 slotIndex.
0x01FA AcceptTrade C→S unhandled P3
0x01FB DeclineTrade C→S unhandled P3
0x0204 ResetTrade C→S unhandled P3
0x0216 ClearPlayerConsentList C→S unhandled P4
0x0217 DisplayPlayerConsentList C→S unhandled P4
0x0218 RemoveFromPlayerConsentList C→S unhandled P4 u32 guid.
0x0219 AddPlayerPermission C→S unhandled P4 u32 guid.
0x021A RemovePlayerPermission C→S unhandled P4 u32 guid.
0x021C BuyHouse C→S unhandled P3 u32 slumlordGuid, PackableListU32 allegianceHouseIds.
0x021E HouseQuery C→S unhandled P3 u32 houseGuid.
0x021F AbandonHouse C→S unhandled P3
0x0221 RentHouse C→S unhandled P3 u32 houseGuid, PackableListU32 itemIds.
0x0224 SetDesiredComponentLevel C→S unhandled P3 u32 level.
0x0245 AddPermanentGuest C→S unhandled P3 string16L name.
0x0246 RemovePermanentGuest C→S unhandled P3 string16L name.
0x0247 SetOpenHouseStatus C→S unhandled P3 bool open.
0x0249 ChangeStoragePermission C→S unhandled P3
0x024A BootSpecificHouseGuest C→S unhandled P3 string16L name.
0x024C RemoveAllStoragePermission C→S unhandled P3
0x024D RequestFullGuestList C→S unhandled P3
0x02540x0256 Allegiance MOTD C→S unhandled P3
0x0258 QueryLord C→S unhandled P3
0x025C AddAllStoragePermission C→S unhandled P3
0x025E RemoveAllPermanentGuests C→S unhandled P3
0x025F BootEveryone C→S unhandled P3
0x0262 TeleToHouse C→S unhandled P3
0x0263 QueryItemMana C→S unhandled P2 u32 guid.
0x0266 SetHooksVisibility C→S unhandled P3 bool visible.
0x0267 ModifyAllegianceGuestPermission C→S unhandled P3
0x0268 ModifyAllegianceStoragePermission C→S unhandled P3
0x02690x026E Chess C→S unhandled P4 Chess minigame.
0x0270 ListAvailableHouses C→S unhandled P3
0x0275 ConfirmationResponse C→S unhandled P2 u32 confirmationType, u32 contextId, bool accepted.
0x0277 BreakAllegianceBoot C→S unhandled P3 u32 otherGuid, bool accountBoot.
0x0278 TeleToMansion C→S unhandled P3
0x0279 Suicide C→S unhandled P3
0x027B AllegianceInfoRequest C→S unhandled P3 string16L name.
0x027D CreateTinkeringTool C→S unhandled P2 u32 ustGuid, u32 targetGuid. Salvage-items-with.
0x0286 SpellbookFilter C→S unhandled P3 Filter bitmap.
0x028D TeleToMarketPlace C→S unhandled P2
0x028F EnterPkLite C→S unhandled P3
0x0290 FellowshipAssignNewLeader C→S unhandled P3 u32 guid.
0x0291 FellowshipChangeOpenness C→S unhandled P3 bool open.
0x02A00x02A7, 0x02AB Allegiance admin C→S unhandled P3 Chat boot / bans / officers.
0x02AF, 0x02B2 Admin plugin query responses C→S unhandled P4
0x0311 FinishBarber C→S unhandled P3 Full barber blob.
0x0316 AbandonContract C→S unhandled P3 u32 contractId.
0xF61B Jump C→S done (partial) P0 Built by Messages/JumpAction.cs. Payload: f32 extent, Vector3 jumpVelocity + position/sequences.
0xF61C MoveToState C→S done P0 Built by Messages/MoveToState.cs. Full RawMotionState + WorldPosition + 4 u16 sequences + contact byte.
0xF61E DoMovementCommand C→S unhandled P4 Legacy — live client doesn't use this path.
0xF649 TurnTo C→S unhandled P4 Legacy — unused.
0xF661 StopMovementCommand C→S unhandled P4 Legacy.
0xF6EA ForceObjectDescSend C→S unhandled P2 u32 guid — ask server to re-emit ObjDescEvent for this entity. Useful for reloading avatar appearance.
0xF745 ObjectCreate C→S unhandled P4 Legacy admin spawn.
0xF747 ObjectDelete C→S unhandled P4 Legacy admin despawn.
0xF74C MovementEvent C→S unhandled P4 Legacy.
0xF750 ApplySoundEffect C→S unhandled P4 Admin.
0xF752 AutonomyLevel C→S unhandled P2 u32 level — ack the server's autonomy level.
0xF753 AutonomousPosition C→S done P0 Built by Messages/AutonomousPosition.cs. Same body as MoveToState but without the motion command list. Heartbeat every ~200ms while moving.
0xF755 ApplyVisualEffect C→S unhandled P4 Admin.
0xF7C9 JumpNonAutonomous C→S unhandled P4 Server-controlled jump — client never sends.

Total GameAction C→S opcodes: 149. Currently handled: 4 (LoginComplete, MoveToState, Jump, AutonomousPosition). Unhandled: 145 — but the vast majority are P3/P4 and unblocking only requires 5-8 P1/P2 adds (ChatChannel, Talk, Tell, Use, UseWithTarget, IdentifyObject, QueryHealth, ChangeCombatMode, CastTargetedSpell, CastUntargetedSpell, TargetedMeleeAttack, TargetedMissileAttack, CancelAttack, PingRequest).


4. GameEvent sub-opcodes (S→C, inside 0xF7B0 envelope)

Wire layout of every GameEvent on the inbound side (source: references/ACE/Source/ACE.Server/Network/GameEvent/GameEventMessage.cs):

u32 0xF7B0                          // GameMessage opcode (GameEvent envelope)
u32 guid                            // session's player guid (0 if session has no player yet)
u32 gameEventSequence               // per-session, incremented by server
u32 eventType                       // one of the values below
<payload bytes>                     // variable
Hex Name Dir Status Prio Payload
0x0003 AllegianceUpdateAborted S→C unhandled P3
0x0004 PopupString S→C unhandled P1 string16L message — modal dialog.
0x0013 PlayerDescription S→C unhandled P0 Large blob — full player stats, skills, attributes, vitals, spellbook, inventory, equipment, titles, contracts. Sent right after LoginComplete. Parsing this is the gate to everything UI.
0x0020 AllegianceUpdate S→C unhandled P3 Allegiance hierarchy delta.
0x0021 FriendsListUpdate S→C unhandled P3 u32 listType, u32 count, FriendEntry[count].
0x0022 InventoryPutObjInContainer S→C unhandled P2 u32 itemGuid, u32 containerGuid, u32 placement.
0x0023 WieldObject S→C unhandled P1 u32 guid, u32 equipLoc, u32 wielderGuid.
0x0029 CharacterTitle S→C unhandled P3
0x002B UpdateTitle S→C unhandled P3 u32 newTitleId.
0x0052 CloseGroundContainer S→C unhandled P2 u32 containerGuid.
0x0062 ApproachVendor / VendorInfoEvent S→C unhandled P2 Vendor inventory blob — item list, buy/sell rates.
0x0075 StartBarber S→C unhandled P3 Barber UI trigger.
0x00A0 InventoryServerSaveFailed S→C unhandled P2 u32 guid — revert a local inventory op.
0x00A3 FellowshipQuit S→C unhandled P3 Echo.
0x00A4 FellowshipDismiss S→C unhandled P3 Echo.
0x00B4 BookDataResponse S→C unhandled P4 Book header + inline pages.
0x00B5 BookModifyPageResponse S→C unhandled P4
0x00B6 BookAddPageResponse S→C unhandled P4
0x00B7 BookDeletePageResponse S→C unhandled P4
0x00B8 BookPageDataResponse S→C unhandled P4 Text of a single page.
0x00C3 IdentifyObject/GetInscriptionResponse S→C unhandled P3 u32 guid, string16L text.
0x00C9 IdentifyObjectResponse S→C unhandled P1 Full AppraiseInfo — properties tables keyed by enum. Essential for target info UI.
0x0147 ChannelBroadcast S→C unhandled P1 u32 channelId, string16L senderName, string16L message.
0x0148 ChannelList S→C unhandled P3 u32 count, string16L[count] names.
0x0149 ChannelIndex S→C unhandled P3
0x0196 ViewContents S→C unhandled P2 u32 containerGuid, u32 count, (u32 guid, u32 slot)[count].
0x019A InventoryPutObjectIn3D S→C unhandled P2 u32 guid — item appears on the ground.
0x01A7 AttackDone S→C unhandled P1 u32 attackSequence, u32 weenieError.
0x01A8 MagicRemoveSpell S→C unhandled P2 u32 spellId.
0x01AC VictimNotification S→C unhandled P1 string16L attackerName, u32 attackerGuid, u32 damageType, u32 damage, u32 hitQuadrant, u32 crit, u32 attackType.
0x01AD KillerNotification S→C unhandled P1 string16L victimName, u32 victimGuid.
0x01B1 AttackerNotification S→C unhandled P1 string16L defenderName, u32 damageType, u32 damage, f32 damagePercent.
0x01B2 DefenderNotification S→C unhandled P1 string16L attackerName, u32 attackerGuid, u32 damageType, u32 damage, u32 hitQuadrant, u32 crit.
0x01B3 EvasionAttackerNotification S→C unhandled P1 string16L defenderName.
0x01B4 EvasionDefenderNotification S→C unhandled P1 string16L attackerName.
0x01B8 CombatCommenceAttack S→C unhandled P1 No payload. "You swing your weapon."
0x01C0 UpdateHealth S→C unhandled P1 u32 targetGuid, f32 healthPercent. Reply to QueryHealth.
0x01C3 QueryAgeResponse S→C unhandled P4
0x01C7 UseDone S→C unhandled P1 u32 weenieError — the Use event's completion signal.
0x01C8 AllegianceAllegianceUpdateDone S→C unhandled P3
0x01C9 FellowshipFellowUpdateDone S→C unhandled P3
0x01CA FellowshipFellowStatsDone S→C unhandled P3
0x01CB ItemAppraiseDone S→C unhandled P4 Ghost — never emitted.
0x01E2 Emote S→C unhandled P1 Same as GM 0x01E0 but GameEvent subclass.
0x01EA PingResponse S→C unhandled P1 u32 clientId echo.
0x01F4 SetSquelchDB S→C unhandled P3 Squelch list sync.
0x01FD RegisterTrade S→C unhandled P3
0x01FE OpenTrade S→C unhandled P3
0x01FF CloseTrade S→C unhandled P3
0x0200 AddToTrade S→C unhandled P3 u32 itemGuid, u32 slotIndex.
0x0201 RemoveFromTrade S→C unhandled P3
0x0202 AcceptTrade S→C unhandled P3 u32 initiatorGuid.
0x0203 DeclineTrade S→C unhandled P3
0x0205 ResetTrade S→C unhandled P3
0x0207 TradeFailure S→C unhandled P3 u32 errorCode.
0x0208 ClearTradeAcceptance S→C unhandled P3
0x021D HouseProfile S→C unhandled P3
0x0225 HouseData S→C unhandled P3
0x0226 HouseStatus S→C unhandled P3
0x0227 UpdateRentTime S→C unhandled P3
0x0228 UpdateRentPayment S→C unhandled P3
0x0248 HouseUpdateRestrictions S→C unhandled P3
0x0257 UpdateHAR S→C unhandled P3
0x0259 HouseTransaction S→C unhandled P3
0x0264 QueryItemManaResponse S→C unhandled P2 u32 itemGuid, f32 manaPercent.
0x0271 AvailableHouses S→C unhandled P3
0x0274 CharacterConfirmationRequest S→C unhandled P2 u32 type, u32 contextId, u32 otherGuid, string16L message.
0x0276 CharacterConfirmationDone S→C unhandled P2 u32 contextId, bool accepted.
0x027A AllegianceLoginNotification S→C unhandled P3
0x027C AllegianceInfoResponse S→C unhandled P3
0x0281 JoinGameResponse S→C unhandled P4 Chess/minigame.
0x0282 StartGame S→C unhandled P0 "World finished loading" signal (duplicate of LoginComplete flow in some clients).
0x0283 MoveResponse S→C unhandled P4 Minigame.
0x0284 OpponentTurn S→C unhandled P4 Minigame.
0x0285 OpponentStalemate S→C unhandled P4 Minigame.
0x028A WeenieError S→C unhandled P1 u32 errorCode — generic game-logic failure (ported from WeenieError enum in shared models).
0x028B WeenieErrorWithString S→C unhandled P1 u32 errorCode, string16L interpolation.
0x028C GameOver S→C unhandled P4 Minigame.
0x0295 SetTurbineChatChannels S→C unhandled P1 u32 count, TurbineChatChannelConfig[count] — configures which chat rooms to show.
0x02AE AdminQueryPluginList S→C unhandled P4
0x02B1 AdminQueryPlugin S→C unhandled P4
0x02B3 AdminQueryPluginResponse S→C unhandled P4
0x02B4 SalvageOperationsResult S→C unhandled P2 Salvage result blob.
0x02BD Tell S→C unhandled P1 string16L message, string16L senderName, u32 senderGuid, u32 targetGuid, u32 chatType.
0x02BE FellowshipFullUpdate S→C unhandled P3
0x02BF FellowshipDisband S→C unhandled P3
0x02C0 FellowshipUpdateFellow S→C unhandled P3 Member delta.
0x02C1 MagicUpdateSpell S→C unhandled P2 u32 spellId. Adds spell to spellbook.
0x02C2 MagicUpdateEnchantment S→C unhandled P1 Enchantment blob — buff/debuff on player.
0x02C3 MagicRemoveEnchantment S→C unhandled P1 u32 layerId, u32 spellId.
0x02C4 MagicUpdateMultipleEnchantments S→C unhandled P1 u32 count, Enchantment[count].
0x02C5 MagicRemoveMultipleEnchantments S→C unhandled P1 Same shape.
0x02C6 MagicPurgeEnchantments S→C unhandled P1
0x02C7 MagicDispelEnchantment S→C unhandled P1 Single dispel.
0x02C8 MagicDispelMultipleEnchantments S→C unhandled P1 Multi dispel.
0x02C9 PortalStormBrewing S→C unhandled P3
0x02CA PortalStormImminent S→C unhandled P3
0x02CB PortalStorm S→C unhandled P3
0x02CC PortalStormSubsided S→C unhandled P3
0x02EB CommunicationTransientString S→C unhandled P1 string16L message, u32 chatType — ticker-style message.
0x0312 MagicPurgeBadEnchantments S→C unhandled P2
0x0314 SendClientContractTrackerTable S→C unhandled P3 Full contract list.
0x0315 SendClientContractTracker S→C unhandled P3 Single contract update.

Total GameEvent opcodes: 94. Currently handled: 0. Unhandled: 94 — the 0xF7B0 path is completely absent from acdream today.


5. Login-phase opcodes

5.1 Order (source: WorldSession.Connect + EnterWorld + holtburger

session/handshake):

  C→S: LoginRequest       (header flag 0x00010000, custom auth body on port N)
  S→C: ConnectRequest     (header flag 0x00040000, returns seeds + cookie + clientId)
       ←200ms race delay→
  C→S: ConnectResponse    (header flag 0x00080000, echo cookie — sent to port N+1)
  S→C: ServerName (GM 0xF7E1)
  S→C: CharacterList (GM 0xF658)
  C→S: CharacterEnterWorldRequest (GM 0xF7C8)
  S→C: CharacterEnterWorldServerReady (GM 0xF7DF)
  C→S: CharacterEnterWorld (GM 0xF657)
  S→C: DDD_Interrogation (GM 0xF7E5)
  C→S: DDD_InterrogationResponse (GM 0xF7E6)
  S→C: PlayerCreate (GM 0xF746) + optional UpdateObjects for initial bubble
  C→S: GameAction(LoginComplete) (GA 0x00A1)
  S→C: GameEvent(PlayerDescription) (GE 0x0013) — full stat sheet
  S→C: GameEvent(SetTurbineChatChannels) (GE 0x0295)
  S→C: many GameMessageCreateObject for the initial bubble

5.2 Timing + latency requirements

  • The 200ms race delay before ConnectResponse is required because the retail client's UDP flow sends the response before the server has finished allocating the session on port N+1. 200ms is the minimum that reliably works against live ACE. Shorter delays cause intermittent "connection refused" from the kernel.
  • Every server packet with Sequence > 0 needs an ack within ~60s regardless of phase (see §1.5). Failing this → Network Timeout.
  • LoginComplete must follow PlayerCreate, not EnterWorld. Sending LoginComplete too early keeps the server in a transitional state and other clients see the player as a purple loading haze.
  • DDD_InterrogationResponse must be sent promptly after receiving DDD_Interrogation (within a few hundred ms). If the server decides DATs are out of sync it will boot the account.
  • If DAT patching is enabled on the server, DDD_Interrogation → DDD_BeginDDD → multiple DDD_DataMessage → DDD_EndDDD can push megabytes of data before LoginComplete is viable.

6. In-world opcodes — functional groups

6.1 Movement (the hot path)

Opcode Dir Cadence Notes
0xF61C MoveToState C→S On key state change Sent when the motion command set changes (start/stop walking, sidestep, turn). Full RawMotionState, position, rotation, sequences, contact byte.
0xF753 AutonomousPosition C→S Every ~200ms while moving Heartbeat confirming the client is still at position X. No motion commands — just position + sequences.
0xF61B Jump C→S On jump key Same structure as MoveToState but with f32 extent, Vector3 velocity prepended.
0xF748 UpdatePosition S→C Per-entity, variable Every entity in the bubble gets these as they move. We parse + fire PositionUpdated.
0xF74C UpdateMotion S→C On motion change NPC starts walking, creature enters combat, door opens, etc.
0xF74E VectorUpdate S→C Per-tick for flying objects Missiles, projectiles, continuous-turn casts. Unhandled today.
0xF751 PlayerTeleport S→C On teleport Player is being moved through portal space. acdream fires TeleportStarted and re-sends LoginComplete at destination.
0xF753 AutonomousPosition S→C On server-forced snap When the server rejects a client-reported position (collision fail, cheat detection), it pushes this to snap the client back.

6.2 Object lifecycle

Opcode Dir Notes
0xF745 CreateObject S→C Initial spawn of anything visible. 538-line parser in Messages/CreateObject.cs.
0xF746 PlayerCreate S→C Special-case of CreateObject for our own player. Same body shape; different semantic. Used as the LoginComplete trigger.
0xF747 ObjectDelete S→C u32 guid, u16 seq. Unhandled — this is the #1 "must add" gap after chat. Without it, stale entities pile up.
0xF7DB UpdateObject S→C Full re-serialize. Used for gear/appearance changes, morphs.
0xF625 ObjDescEvent S→C Visual-description-only re-send. Lighter than UpdateObject.
0xF6EA ForceObjectDescSend bi Client can C→S to refresh; server sends S→C to force.

6.3 Chat (primary channel)

Opcode Dir Notes
GA 0x0015 Talk C→S Local area say.
GA 0x005D Tell C→S Whisper by name.
GA 0x0032 TalkDirect C→S Whisper by target.
GA 0x0147 ChatChannel C→S Send to named channel.
GA 0x01DF Emote C→S /e text.
GM 0x02BB HearSpeech S→C Nearby chat.
GM 0x02BC HearRangedSpeech S→C Shouts.
GM 0x01E0 EmoteText S→C Environmental emote.
GE 0x02BD Tell S→C Whisper inbound.
GE 0x0147 ChannelBroadcast S→C Custom channel line.
GM 0xF7E0 ServerMessage S→C System chat.
GM 0xF7DE TurbineChat bi Turbine's social chat (General/Trade/LFG/Allegiance/Society). Nested binary blob — non-trivial parser.
GE 0x0295 SetTurbineChatChannels S→C Configure Turbine chat rooms on login.

6.4 Combat

Opcode Dir Notes
GA 0x0008 TargetedMeleeAttack C→S targetGuid, attackHeight, powerLevel.
GA 0x000A TargetedMissileAttack C→S targetGuid, attackHeight, accuracyLevel.
GA 0x01B7 CancelAttack C→S
GA 0x0053 ChangeCombatMode C→S Peace/Melee/Missile/Magic.
GA 0x01BF QueryHealth C→S Request health % for a target.
GE 0x01C0 UpdateHealth S→C Reply to QueryHealth; f32 healthPercent.
GE 0x01A7 AttackDone S→C End-of-swing.
GE 0x01AC VictimNotification S→C You took damage.
GE 0x01AD KillerNotification S→C You killed X.
GE 0x01B1 AttackerNotification S→C You did damage.
GE 0x01B2 DefenderNotification S→C You were attacked.
GE 0x01B3 EvasionAttackerNotification S→C Target dodged you.
GE 0x01B4 EvasionDefenderNotification S→C You dodged.
GE 0x01B8 CombatCommenceAttack S→C Swing-start flag.
GM 0x019E PlayerKilled S→C Fatal blow.

6.5 Spells & enchantments

Opcode Dir Notes
GA 0x0048 CastUntargetedSpell C→S u32 spellId.
GA 0x004A CastTargetedSpell C→S u32 targetGuid, u32 spellId.
GA 0x01A8 RemoveSpellC2S C→S Un-learn a spell.
GA 0x01E3/0x01E4 Add/RemoveSpellFavorite C→S Hotbar slot management.
GE 0x02C1 MagicUpdateSpell S→C Add/refresh a spellbook entry.
GE 0x02C2 MagicUpdateEnchantment S→C Buff/debuff applied.
GE 0x02C3 MagicRemoveEnchantment S→C Buff expired/dispelled.
GE 0x02C4/0x02C5 MagicUpdate/RemoveMultiple S→C Batch variants.
GE 0x02C6 MagicPurgeEnchantments S→C Full clear.
GE 0x0312 MagicPurgeBadEnchantments S→C Clear debuffs only.
GE 0x02C7/0x02C8 MagicDispel[Multiple]Enchantment S→C Dispelled-by-player.
GE 0x01A8 MagicRemoveSpell S→C Spell removed from book.

6.6 Inventory & items

Opcode Dir Notes
GA 0x0019 PutItemInContainer C→S itemGuid, containerGuid, placement.
GA 0x001A GetAndWieldItem C→S Pick up and equip in one step.
GA 0x001B DropItem C→S
GA 0x0036 Use C→S
GA 0x0035 UseWithTarget C→S
GA 0x00C8 IdentifyObject C→S
GA 0x0054/0x0055/0x0056 Stackable* C→S Split / merge.
GA 0x005F/0x0060 Buy/Sell C→S
GE 0x0022 InventoryPutObjInContainer S→C
GE 0x0023 WieldObject S→C
GE 0x019A InventoryPutObjectIn3D S→C Dropped to ground.
GE 0x0196 ViewContents S→C Container list.
GE 0x00C9 IdentifyObjectResponse S→C Appraise reply.
GE 0x0062 ApproachVendor S→C Vendor inventory.
GM 0xF74A PickupEvent S→C Pickup animation flag.
GM 0x0024 InventoryRemoveObject S→C
GM 0x0197 SetStackSize S→C
GM 0xF749 ParentEvent S→C Equip / attach.

7. Frequency / priority

Rank Rate (approx, with 10 other players nearby) Opcodes Why
Very hot 2-5 Hz per player, per creature UpdatePosition, UpdateMotion, AutonomousPosition (both directions) Physics sync. Must not allocate on hot path.
Hot ~0.5 Hz per player VectorUpdate, MoveToState Movement delta.
Warm ~1 msg every few seconds HearSpeech, ChannelBroadcast, Tell, EmoteText, UpdateHealth, attack notifications Chat + combat feedback.
Cool ~1 msg / min ObjectCreate bursts on bubble enter, ObjectDelete on bubble exit, UpdateObject on gear swap Bubble churn.
Cold Once per session or event CharacterList, DDD, LoginComplete, PlayerDescription, SetTurbineChatChannels, PlayerKilled, PlayerTeleport Login + rare triggers.
Background Driven by player action Use, IdentifyObject, Buy, PingRequest, spell casting Player explicit.

Planning implication: the top two tiers (physics sync) must be zero-allocation parses. acdream's current CreateObject.TryParse and UpdatePosition.TryParse already are — they use ReadOnlySpan<byte> and BinaryPrimitives. New parsers should match that pattern.


8. Gap analysis — what's missing for minimum viable play

Grouped by how much they unblock:

8.1 P0 / session health (must-have for any session to survive)

  • 0xF747 ObjectDelete — without this, stale entities pile up forever. High impact, ~30-line parser, emit EntityDespawned event.
  • 0xF752 AutonomyLevel (S→C) — parse and store. ACE live sends this regularly; ignoring it is fine today but we should not crash on unknown payloads.
  • 0xF7DC AccountBoot — transition to Failed with the server's reason string instead of a timeout.
  • 0xF659 CharacterError — surface login failures as errors rather than a CharacterList timeout.

8.2 P1 / basic in-world feedback (first thing a user will miss)

  • Chat stack: 0x02BB HearSpeech, 0x02BC HearRangedSpeech, 0x01E0 EmoteText, 0xF7E0 ServerMessage, 0xF7B0/0x0147 ChannelBroadcast, 0xF7B0/0x02BD Tell, 0xF7B0/0x02EB CommunicationTransientString, 0xF7B0/0x0004 PopupString. Plus outbound 0xF7B1/0x0015 Talk, /0x005D Tell, /0x0147 ChatChannel, /0x01DF Emote.
  • Property updates (0x02CD..0x02EA): 22 opcodes, but they all share a compact pattern — u32 guid, u32 propId, value. One generic parser + 8 value-type branches covers everything. Fires per-property events.
  • GameEvent envelope (0xF7B0): must ship the dispatcher skeleton before any GameEvent can be handled.
  • Combat events (0x01AC..0x01B8): receiving only; one parser per message. Lets floating combat text + hit indicators work.
  • 0x02C2/0x02C4 Magic[Multiple]UpdateEnchantment + 0x02C3/0x02C5 remove: buff/debuff HUD.
  • 0xF625 ObjDescEvent + 0xF7DB UpdateObject: for seeing other players change gear. Critical for multiplayer immersion.
  • GameEvent PlayerDescription (0x0013) — initial character sheet. Gate for inventory/spellbook UI. Biggest message in the protocol — ~30 KB of interleaved property tables.

8.3 P2 / inventory, assess, vendor

  • 0x00C9 IdentifyObjectResponse + GA 0x00C8 IdentifyObject.
  • Full inventory flow: GA 0x0019, 0x001A, 0x001B, 0x0054-0x0056, and the mirror GameEvents 0x0022, 0x0023, 0x019A, 0x0196.
  • GE 0x0062 ApproachVendor + GA 0x005F Buy / 0x0060 Sell.
  • GA 0x0036 Use + 0x0035 UseWithTarget + GE 0x01C7 UseDone.

8.4 P3 / social, housing, allegiance

Large opcode count but highly modular — each subsystem is ~15-20 opcodes. Skip until post-beta.

8.5 P4 / admin, minigames, barber, char-create

Zero visibility impact for combat-focused play. Park.


9. Port plan — where the WorldSession dispatcher needs to expand

9.1 Refactor the dispatcher skeleton first (phase D prerequisite)

Today WorldSession.ProcessDatagram is a long if/else ladder. Before adding more handlers, split it into a dispatcher class. Layout:

AcDream.Core.Net/
├── Messages/
│   ├── GameMessageDispatcher.cs        // top-level opcode → parser router
│   ├── GameEventDispatcher.cs          // inside 0xF7B0
│   ├── GameActionBuilder.cs            // fluent builder for 0xF7B1 envelope
│   └── <one file per opcode group>
└── WorldSession.cs                     // becomes thin, delegates to above

Each dispatcher exposes register<T>(opcode, parser) so phase D can bolt on new handlers without modifying the dispatcher class body.

9.2 Phase D — chat + session health

Scope:

  • Add the GameEvent envelope dispatcher (0xF7B0).
  • Ship ObjectDelete (0xF747), AutonomyLevel (0xF752), AccountBoot (0xF7DC), CharacterError (0xF659).
  • Ship the chat group (11 opcodes) + outbound Talk/Tell/ChatChannel.
  • Ship PopupString, CommunicationTransientString, SetTurbineChatChannels as UI sidechannels.
  • Add an IChatSurface event set on WorldSession: Said, Whispered, ChannelMessage, SystemMessage, Popup, Transient.

Acceptance: log in, receive and post chat, see server announcements, get kicked gracefully.

9.3 Phase E — property & stats

Scope:

  • Ship the 22 property-update opcodes behind one generic PropertyUpdateParser keyed on PropertyId.
  • Ship PlayerDescription (GE 0x0013) — the single biggest parser job.
  • Ship UpdateHealth (GE 0x01C0), QueryHealth (GA 0x01BF).
  • Ship ObjDescEvent (0xF625), UpdateObject (0xF7DB).
  • Expose IPlayer interface that plugins can observe: Attributes, Skills, Vitals, Inventory, Spellbook.

Acceptance: stat sheet renders correctly, health bars update live, can assess nearby NPCs.

9.4 Phase F — combat + spells

Scope:

  • Ship combat notifications (0x01AC..0x01B8).
  • Ship attack actions (GA 0x0008, 0x000A, 0x01B7, 0x0053).
  • Ship enchantments (GE 0x02C1..0x02C8, 0x0312).
  • Ship cast actions (GA 0x0048, 0x004A).

Acceptance: can kill a lurker, see float text + health, land a self-buff and watch it tick.

9.5 Phase G — inventory

Scope:

  • Ship the GA/GE inventory families.
  • Ship ApproachVendor + Buy/Sell.
  • Ship PickupEvent + ParentEvent.

Acceptance: loot a drudge, sell to vendor, equip a weapon, see it render on the avatar.

9.6 Deferred: housing, allegiance, fellowship, books, barber, chess

All the P3/P4 tails. Ship when we need them, not before.


10. Collision + sub-type notes (the ultrathink)

  • 0xF643 CharacterCreateResponse vs CharacterRestoreResponse. Same opcode, two meanings. Disambiguated entirely by session state — if the client just sent 0xF656 CharacterCreate the reply is a create response; if it just sent 0xF7D9 CharacterRestore it's a restore response. Parsers must key on context, not opcode. ACE has a duplicate entry in the enum (CharacterRestoreResponse = 0xF643, // This is a duplicate...). Holtburger keeps them combined under CharacterCreateResponse.
  • 0xF74C: MovementEvent and Motion are the same opcode. ACE aliases Motion = 0xF74C and MovementEvent = 0xF74C — semantically identical, just two names. Our UpdateMotion.cs already handles this.
  • 0xF753 AutonomousPosition goes both ways with the same body layout but different semantics. Outbound = "I'm still here"; inbound = "no you're not, here's where you really are." Parser can be shared; the client just needs to know direction to choose the right side-effect (PositionUpdated vs ForcedResync).
  • 0x0147 ChatChannel vs ChannelBroadcast. C→S uses 0x0147 inside GameAction (envelope 0xF7B1); S→C uses 0x0147 inside GameEvent (envelope 0xF7B0). Same wire opcode, different parser because different envelope. This is true for many ID collisions — the envelope disambiguates them.
  • 0x0148/0x0149 Channel List/Index — same C→S/S→C pairing pattern.
  • 0x00A3/0x00A4 FellowshipQuit/Dismiss — same pairing; C→S in GameAction, S→C in GameEvent.
  • 0xF653 CharacterLogOff — bi-directional, same opcode, no envelope. Client sends to request logout; server sends the echo before Disconnect.
  • 0x01A8 MagicRemoveSpell — C→S is GameAction, S→C is GameEvent.
  • 0xF7DE TurbineChat — bi-directional GameMessage. Blob layout includes a ChatNetworkBlobType discriminant (EVENT_BINARY=1, REQUEST_BINARY=3, RESPONSE_BINARY=5) + a ChatNetworkBlobDispatchType sub-discriminant (SendToRoomByID=1/2). Effectively two opcodes (event vs request/response) multiplexed on one wire code. Nested "bytes to follow" size prefixes must be back-patched after payload writes — non-trivial parser.
  • 0xF6EA ForceObjectDescSend — bi-directional with identical u32 guid body. The side-effect differs: server takes it as "resend to me"; client takes it as "apply a fresh ObjDescEvent I'm about to receive."

11. Source of truth ranking (per opcode category)

When the references disagree, use this priority:

  • PacketHeader + Flags + encryption: ACE and holtburger agree on all bits. No disputes.
  • C→S GameAction opcodes: holtburger's opcodes.rs is the most curated list of what a real client actually sends. ACE's GameActionType.cs is the full universe including things only legacy admin tools ever sent. Use holtburger when in doubt about which GAs are relevant; use ACE when you need the wire layout of a specific handler.
  • S→C GameMessage opcodes: ACE's GameMessageOpcode.cs is the canonical enum; Chorizite's XML adds field-level comments that are sometimes more accurate than ACE's implementation (remember "If it is 0, it defaults to 256*8"). Use ACE for structure; use Chorizite to cross-check specific field semantics.
  • S→C GameEvent opcodes: ACE's GameEventType.cs + the per-event classes in Events/ are the wire ground truth.
  • RawMotionState wire: holtburger types.rs is the only source that documents every flag bit clearly; ACE has the same structure but embedded in MovementData.Pack.
  • PositionPack (for UpdatePosition): ACE's PositionPack.Write is the canonical serializer; holtburger matches bit-for-bit.
  • TurbineChat nested blob: ACE's GameMessageTurbineChat has a large comment block documenting every field layout. Holtburger's implementation matches.

12. Quick-reference: what to add first if you have one afternoon

Pick four opcodes from the P0/P1 tier and you have a meaningfully more useful client by end-of-day:

  1. 0xF747 ObjectDelete — stop leaking entities (20 lines).
  2. 0xF7B0 GameEvent envelope skeleton — unlocks the whole event category (50 lines dispatcher).
  3. 0x02BB HearSpeech + 0x02BC HearRangedSpeech — see world chat (same parser, different trigger; 30 lines each).
  4. 0xF7E0 ServerMessage — see system chat (20 lines).

That's ~150 lines of parser code and acdream graduates from "renders the world" to "reads the world's feedback."