Professional Documents
Culture Documents
Lu Packet Structs
Lu Packet Structs
Introduction:
The purpose of this documentation is to list and protocol all the information about the network
packets of the game LEGO Universe.
The documentation is organized into separate sub-documents:
Client Packets
Server Packets
Chardata Packet XML Structure
Replica Packets
Game Messages
Game Mechanics
File Structures
The format used to describe binary structures is documented in the doc Structure Definition
Format.
If any of these documents helped you in some way or another for one of your projects then
please credit us and/or include a direct link to this document.
Disclaimer:
LEGO is in no way affiliated with the content of this and the aforementioned documents.
Furthermore the creators of the just mentioned documents are not associated or involved with
LEGO.
Contact Info:
Most developer activity happens on the LEGO Universe Community Hub (LUCH) discord
nowadays. If you join there and ask a question, it’s quite likely someone will be able to help you
out. Devs from all major server projects are active in LUCH.
If you want to contact lcdr, you can also do so via twitter, the lcdr Universe forums, and the lcdr
Universe discord.
Server:
- The client uses the RakNet network library (v3.25) to communicate with the server,
therefore it is recommended to use it in the server if you want to work on one and are
new to this project.
You can download it here (documentation and sample projects are included), note that
later versions of the library won’t work due to changes in the network protocol.
Alternatively lcdr wrote a python version with the minimum features needed to run a
server for the game implemented, available here (no documentation yet so not
recommended for inexperienced users)
- The listening port for the Authentication Server is hardcoded to 1001 (UDP), the ports for
the following instances (char, world) depend on what the Authentication Server sends to
the client but the port range used for the original servers was 2001-2200 (UDP)
- In order for the server to establish a working connection with the client it is required to
set up a pre-set password in RakNet by calling “SetIncomingPassword("3.25 ND1", 8);”
for the RakPeerInterface instance before listening for packets
- It seems that the server used the “SYSTEM_PRIORITY” and “RELIABLE_ORDERED” options for
all outgoing packets to the client (though that's probably not a requirement)
- The template for the ZoneControl object is located at the ZoneTable table. If NULL, the
default template is 2365. It’s objectID seems to be a spawnerID and is (2^46 - 2).
- The game had 3 different performance configurations for the physic engine on each
world declared at the ZoneTable. (high = ???, medium = ???, low = ???, default:
medium)
- According to activities, LU Servers used Microsoft ActiveX Data Objects.
- If an object’s collision type is set to HKX, but no path is given, it will use a 2x2x2 cube.
Packet Captures:
Thanks to pwjones we have access to quite a lot of (partial) traffic sessions of the original server
which serve as a basis for this documentation, if you want to dig into them yourself, here is a
download link. The captures are contained within the .rar files, make sure to extract them (as
well as the .zip containing them if you downloaded the folder as a .zip).
Since the original captures (*.pcap files) were encrypted by RakNet it was required to decrypt
them again (*.bin files stored in *.zip archives where each archive represents a session) which
was only possible using a piece of information that RakNet exchanges at the beginning of a
traffic.
Extracting the entire .zip capture(s) is not recommended, since this many files (several ten
thousand) will have a huge overhead on the file system (because of things like last modified
info, which isn’t applicable here anyways), resulting in a much larger file space consumption and
slower access times when trying to list the files in the explorer.
If you want to search multiple captures for specific files, use this script:
https://github.com/lcdr/utils/ find_packets.py
(The script also yields the binary content of the packets, which can be useful for further filtering
or logging)
If you want to look at the raw data of a packet yourself (not recommended for inexperienced
users) you can of course extract single files from the .zip archive using an archive extractor of
your choice (I recommend 7-Zip).
Then you can open the extracted *.bin file(s) using a hex editor of your choice (for some packet
types it might be useful to have an editor that can shift the bits in the data, no recommendation
here).
Alternatively a graphical viewer for capture files is available at https://github.com/lcdr/utils/
captureviewer.py (takes the entire .zip archive of a traffic as input, no need to extract anything)
Packet Documentation:
We can’t guarantee that all the packet structures listed here are correct, the only way to do that
would be to have access to the original source code that created them. In fact, there are a
number of packets and structures where we can only guess, or don’t know their purpose at all.
(Typically structures with an unknown purpose will be marked as “???”).
If you notice that information in these docs is incorrect, please edit it, and leave a comment with
your sources. We may not be able to confirm your edits right away, and they might stay marked
as suggestions for a while. This does not mean that we don’t approve of your edit, just that we
haven’t gotten around to confirming it yet. We appreciate every edit you submit, and we’re
always happy to improve the accuracy or the wording of this documentation. However to make
sure that the information stated here is actually correct we can’t merge edits immediately.
Reference:
[xx-xx-xx-xx]: first 4 bytes of the header (this matches the decrypted packet file names in the
captures)
Artificial packet: Packet was not captured in traffic logs, but tests with the ID show that it is
recognized by the client.
Theoretical packet: Packet was not captured in traffic logs, but there is evidence in the client
executable that the packet has this purpose. For server packets, once tests with the ID show
that the client reacts to the packet, this should be changed to Artificial packet. For client
packets, once we manage to get the client to send a packet of this type, this should be changed
to normal packet.
u8: unsigned char (1 byte)
u16: unsigned short (2 bytes)
u32: unsigned long (4 bytes)
u64: unsigned long long (8 bytes)
s32: signed long (4 bytes)
s64: signed long long (8 bytes)
bool: boolean, can either be 1 or 0 (1 byte)
bit: “true” boolean, can either be 0 or 1, if there is a “flag” specifier then this defines whether a
part of a packet (all structures that are indented one additional level) is included or not (1 bit)
string: char sequence (x bytes, null terminated (zero at the end)), 33 bytes long
wstring: wide char sequence (2*x bytes, null terminated (double zero at the end)), 66 bytes
long
(there are variants of these string types that are variable-length, they should be explicitly stated
as variable length or somehow else be distinguished from the types above)
LDF: Lego data format, our unofficial name for the data format used in packets and
configuration files (so far in binary, xml and config variations), see Appendix for definition
LOT: ”Lego Object Template”?, determines the kind of object (whether it’s a player, an NPC, a
tree, etc) and which components the object has (4 bytes)
Object ID: ID to distinguish each object in the game (e.g. player characters) (8 bytes)
Network ID: Temporary ID added by Raknet’s ReplicaManager, this is handled automatically
and usually not important. Used to internally address objects for updates/destruction
Packet Header:
[u8] - RakNet packet ID, typically 0x53 for packets that are not being handled by RakNet (which
are practically all packets that will be listed here)
if packet id is 0x53:
[u16] - type of the remote connection, is exchanged in the first two packets of the real traffic,
should be one of these values: 0 (general), 1 (auth), 2 (chat), 4 (server), 5 (client)
[u32] - packet ID, to be able to identify what the packet contains (which will also be done in this
document), could be that the latter 2 bytes are another u16 struct but they have always been 0
so far
[u8] - ???, is always 0? could be padded data
Packet List:
Format:
[header] - according enum name taken from the client executable ( - more descriptive name)
Packet Colors:
green: is available in the captured traffics (or could be reproduced to be sent from the client)
yellow: is not available but self-created ones were effectively tested (Artificial packet)
red: is not available and no testing was done yet or it had no effect (Theoretical packet)
grey: has been proven to be unused in the client through reverse engineering
Server-to-Client:
[53-02-00-03] (unused)
Left in the game but has empty function body
[53-02-00-21] (???)
???
Client-to-Server:
In a few places, like boot.cfg, client xml settings, inside .luz and .lvl files, and the chardata
packet, a custom name-value storage format is used. We’ve termed this “LEGO data format” or
LDF for short, although this is not the official name. The official name was likely
“LWONameValue” (but that’s hard to abbreviate).
There are two versions of this format, one is text-based, while the other is binary.
The binary data format is used in various packets, for example the chardata packet.
The structure is as follows:
The text format is used in boot.cfg and in .luz & .lvl files.
The text format has the format:
key name=type:value
The used data type IDs are the same for both text and binary. These are the types we’ve been
able to match so far: