# packet-protocol > Implements L2 binary protocol networking and client-server communication. Use when: creating new client/server packets, debugging network issues, implementing protocol features, modifying packet handlers, or understanding the L2J networking architecture - Author: valeriybaranyshyn-pixel - Repository: valeriybaranyshyn-pixel/Tales-of-Aden - Version: 20260202145225 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/valeriybaranyshyn-pixel/Tales-of-Aden - Web: https://mule.run/skillshub/@@valeriybaranyshyn-pixel/Tales-of-Aden~packet-protocol:20260202145225 --- --- name: packet-protocol description: | Implements L2 binary protocol networking and client-server communication. Use when: creating new client/server packets, debugging network issues, implementing protocol features, modifying packet handlers, or understanding the L2J networking architecture allowed-tools: Read, Edit, Write, Glob, Grep, Bash --- # Packet Protocol Skill L2J uses a custom binary protocol over TCP with NIO for high-performance MMO networking. The architecture separates concerns into MMOCore (reusable NIO framework), encryption layers (XOR for game, RSA+Blowfish for login), and state-based packet handlers. All packets use little-endian byte order with a 2-byte length header. ## Quick Start ### Creating a Client Packet ```java // Files/java/net/sf/l2j/gameserver/network/clientpackets/RequestExample.java public class RequestExample extends L2GameClientPacket { private int _itemId; private String _message; @Override protected void readImpl() { _itemId = readD(); // 4 bytes int _message = readS(); // null-terminated UTF-16LE string } @Override protected void runImpl() { final Player player = getClient().getActiveChar(); if (player == null) return; // Business logic here player.sendPacket(new ExampleResponse(_itemId)); } } ``` ### Creating a Server Packet ```java // Files/java/net/sf/l2j/gameserver/network/serverpackets/ExampleResponse.java public class ExampleResponse extends L2GameServerPacket { private final int _result; public ExampleResponse(int result) { _result = result; } @Override protected void writeImpl() { writeC(0xFE); // Extended opcode marker writeH(0x00); // Extended opcode writeD(_result); // 4 bytes int writeS("Success"); // null-terminated UTF-16LE } } ``` ## Key Concepts | Method | Size | Type | Notes | |--------|------|------|-------| | `readC()/writeC()` | 1 byte | unsigned 0-255 | Opcodes, flags | | `readH()/writeH()` | 2 bytes | unsigned short | Item counts, IDs | | `readD()/writeD()` | 4 bytes | signed int | Object IDs, coordinates | | `readQ()/writeQ()` | 8 bytes | long | Adena, timestamps | | `readF()/writeF()` | 8 bytes | double | Positions, damage | | `readS()/writeS()` | variable | UTF-16LE null-term | Names, messages | | `readB()/writeB()` | variable | raw bytes | Crypto keys, blobs | ## Common Patterns ### Static Singleton for Immutable Packets **When:** Packet has no dynamic data (saves allocations) ```java public final class ActionFailed extends L2GameServerPacket { public static final ActionFailed STATIC_PACKET = new ActionFailed(); private ActionFailed() {} @Override protected void writeImpl() { writeC(0x25); // Just the opcode, no data } } // Usage: player.sendPacket(ActionFailed.STATIC_PACKET); ``` ### Registering New Opcodes Add to `L2GamePacketHandler.handlePacket()` switch statement under the appropriate state: ```java case IN_GAME: switch (opcode) { // ... existing opcodes case 0xXX: msg = new RequestExample(); break; } ``` ## See Also - [patterns](references/patterns.md) - Packet structure patterns, encryption, state machines - [workflows](references/workflows.md) - Adding packets, debugging, testing ## Related Skills - See the **l2j-gameserver** skill for server architecture - See the **l2j-loginserver** skill for authentication protocol - See the **java** skill for coding conventions