All related configuration files are under
Supported protocol configuration can be altered by modifying the
There isn't much to say about auth protocols, because they hardly change and the protocol revision number is just cosmetic. You shouldn't need to change them.
Let's start with an example:
<protocol id="54" alias="Infinite Odyssey" category="IO"> <version date="2015-04-22">24</version> <primary> <constant>0x12</constant> <constant>0xB1</constant> <constant>0x11</constant> <constant>0xD0</constant> </primary> <secondary count="269"> <constant>0x70</constant> <constant>0x71</constant> </secondary> <definitions dir="infinite_odyssey" /> </protocol>
<protocol> element attributes:
id: currently unused. Designed to be used for programmatic protocol version comparisons instead of the hardcoded
alias: user-friendly protocol description string (yes, it will be displayed to the user).
category: user-friendly protocol category string. Used to build GUI submenus related to protocol display configuration.
disabled: boolean that controls whether to ignore a definition.
<version>: protocol revision number, as known to the associated client. Attribute
dateis used for version comparisons.
<primary>: CM opcode shuffling control. See below.
<secondary>: CM opcode shuffling control. See below.
dirspecifies the relative directory for packet definitions.
CM opcode shuffling
Client packet opcode shuffling feature was first implemented in Hellbound (831). Shuffling happens on two occassions:
- Initial login (to the game server lobby)
- Each time a concrete character is logged in
Shuffle results depend on the total amount of opcodes to be shuffled (e.g., if there are 5 in total, opcode 6 will never be used after shuffling). Moreover, certain opcodes
may be deemed constant: they will not participate in the shuffle.
<secondary> elements allow these options to be configured.
count attribute may be used to specify the total amount of opcodes (NetPro will log warnings if this is set too low). There is no sense in setting the count of primary opcodes,
because with introduction of
0xCF (which changed to
0xD0 in C4 – years before shuffling was implemented), the amount of primary opcodes never changes.
<constant> subelements may be used to specify which opcode values should not participate in the shuffling algorithm.
Packet names are defined in
all_known_packets.xml. As you have found out while reading about protocol definitions, actual definitions are contained in named subdirectories of
Each such subdirectory may contain up to 3 elements:
client/: CM definition folder
server/: SM definition folder
opcode_mapping.xml: a specification of what packets have which opcode values
The opcode mapping specification file is a critical component in incremental packet definition loading. Opcode mappings themselves are loaded incrementally as well.
The structure of this file is completely self-explanatory (see the associated XML schema for details). Packet IDs and visible names are defined in
Known major opcode re-assignments are C2 (SMs) and Kamael (all).
Names of these subfolders are rather self-explanatory. They contain XML files with packet definitions, one definition per file. The recommended definition file naming scheme is
[name of the packet as found in the latest available client].xml, even though you may name them arbitrarily (keep the
.xml extension) if that helps you in any way.
It is not required to keep these folders if they are empty.
Packet definition file
A packet definition file is a sequence of fields, loops and branches associated with an ID defined in
<unsignedByte>: 8-bit integer (
byteand no direct equivalent in Java)
<unsignedWord>: 16-bit integer (
<dword>: 32-bit integer (
<word>: 64-bit integer (
<single>: IEEE single-precision float (
<double>: IEEE double-precision float (
<string>): nul-terminated UTF-16 (LE) string
<sstring>: sized UTF-16 (LE) string. The string itself is preceeded by a 16-bit integer specifying string length (in characters).
Field value presentation
More often than not, fields values do not have a direct meaning (e.g. PvP count is exactly what it says on the tin, while a world object ID merely points to some object; plus, there are different types of world objects).
A field may specify an interpreter class using the
type attribute to change the way field values are presented. While some of you may know the numeric equivalents of all character classes,
learning all skill level names and enchant routes may pose a notably harder challenge.
<byte alias="Mount type" type="MountType" /> <byte alias="Private store" type="PersonalStoreType" /> <dword alias="Mount" type="Npc" /> <dword alias="Class" type="CharacterClass" />
<loop> element allows its subelements to be read an arbitrary amount of times. It is assumed that loop size is always dynamic, and the
id attribute controls which integer field's
[modified] value is used as iteration count. The associated integer field should have a matching
id attribute, e.g.
<dword alias="Available recipes" id="cnt" /> <loop id="cnt"> <dword alias="Recipe" type="Recipe" /> <dword alias="Can create" type="YesOrNo" /> </loop>
<branch> element allows its subelements to be read conditionally. The
id attribute identifies the field to be tested (that field must have a matching
id attribute value) using logic
found in the conditional class identified by attribute
condition. Condition classes are found in the script
condition package (and its subpackages); in the class name, only specify
subpackages (if any; do not use FQCN).
<byte alias="Parameter" type="Parameter" id="param" /> <branch id="param" condition="param.StringValue"> <string alias="Value" /> </branch>