Subsections of Packets

Creating packets

Learning

This site contains a description of the packets used in the Minecraft back-end.
Select the core version on the website on which the server is located and click on the link of this version.
First, we need to find the packet that we need. All packets located in the SERVERBOUND section - packets are sent to the server players in the CLIENTBOUND section - from the server to the player. We are obviously interested in the packets section CLIENTBOUND.
Let’s choose a packet SET CAMERA , since it has not changed since version 1.8.
This packet allows you to set a camera for the player, similar to the camera that occurs when you click on an entity in spectator mode.
We see the following table on the website:

Packet IDStateBound ToField NameField TypeNotes
0x50PlayClientCamera IDVarIntID of the entity to set the client’s camera to.

This table contains the packet number, the moment of gameplay when it can be received, what the packet is linked to, and a description of its contents.
First of all, we need to find out what this packet is called on the server. To do this, we will need the first three fields:

  • id
  • state
  • bound

Getting the packet name

[wrapped] packet name (by|of) id %number% [(and|,)] state %string% [(and|,)] bound %string%

ID on the site is indicated by a number in the hexadecimal, using the module Bitwise we can specify the value as described on the site, or convert the number from the site to the decimal (choose which is more convenient for you).

on load:
  broadcast packet name of id 0x50 and state "play" and bound "client"

After loading script, the name of this packet will be written in the chat - PacketPlayOutCamera.
We won’t need any more code above, it was necessary to find out the name of the packet.
Next, we need to fill the buffer with the data described in the columns Field Name, Field Type, Notes.
We will fill in a new structure - ByteBuf. It is a set of bytes into which bytes can be written and read.

Creating a buffer

The expression below is used to create an empty buffer:

empty buffer
command packet_example:
  trigger:
    set {_buffer} to empty buffer

Filling the buffer with data

The following expressions are used to write to the buffer:

write bytes %bytebuf% to %bytebuf%
write bool[ean] %boolean% to %bytebuf%
write uuid %string% to %bytebuf%
write string %string% to %bytebuf%
write utf[-| ]8 %string% to %bytebuf%
write position %vector% to %bytebuf%
write position %location% to %bytebuf%
write [unsigned] byte %number% to %bytebuf%
write [unsigned] short %number% to %bytebuf%
write float %number% to %bytebuf%
write double %number% to %bytebuf%
write int[eger] %number% to %bytebuf%
write long %number% to %bytebuf%
write angle %number% to %bytebuf%
write var[iable][ ]int[eger] %number% to %bytebuf%
write var[iable][ ]long %number% to %bytebuf%

Each expression provides a specific type, described in the section Data type on wiki .
Some complex types described on the site can be made up of simple ones, so they are missing in expressions.
Packet PacketPlayOutCamera accepts a field with the type VarInt and a value equal to the entity ID.
To get the identifier use the following expression .
From the table, we know that you need to write this identifier with the type VarInt. Let’s use the necessary expression:

command packet_example:
  trigger:
    set {_buffer} to empty buffer
    set {_entity} to target entity of player
    set {_id} to entity id of {_entity}
    write varint {_id} to {_buffer}

Since the table no longer contains data, we can create a packet from the buffer by its name.

Write index

Each write to the buffer shifts its Writer index, which is the number of bytes written inside the buffer.
Writer index you can find out or change it using the following expression:

writer index of %bytebuf%
%bytebuf%'s writer index

Creating a packet from a buffer

The expression below allows you to create a packet based on the packet name and the filled buffer for subsequent sending.

[create] packet %string% (from|of|with) %bytebuf%
command packet_example:
  trigger:
    set {_buffer} to empty buffer
    set {_entity} to target entity of player
    set {_id} to entity id of {_entity}
    write varint {_id} to {_buffer}
    set {_packet} to create packet "PacketPlayOutCamera" with {_buffer}

We have created our first packet, it remains only to send it to the player.

Sending packets

The following expression is used to send packets:

send packet %packets% to %players%

The expressions below allow you to send a packet without calling an event on packet

send packet %packets%  without [(trigger|call)[ing]] [the] event to %players%
send packet %packets% to %players%  without [(trigger|call)[ing]] [the] event
command /entitycam:
  trigger:
    set {_buffer} to empty buffer
    set {_entity} to target entity of player
    set {_id} to entity id of {_entity}
    write varint {_id} to {_buffer}
    set {_packet} to create packet "PacketPlayOutCamera" with {_buffer}
    send packet {_packet} to player

To check the operability of the code above, aim your cursor at any entity, and then send the command /entitycam.
After executing the command, you will be looking from the entity’s face, even if you are not in spectator mode.

This way you can create any packet by following the steps described above.

Packet handling

The event of receiving or sending a packet.

This event allows you to trigger code when a packet is received (Client -> Server) or sent (Server -> Client).

on packet:
on packet %packet name%:


The event can be canceled. In this case, the packet will not be received or sent (respectively).

This event has built-in expressions.

  • event-packet - to receive the packet
  • event-player - to get a player

event-packet can be replaced with set event-packet to %packet%, provided that no execution delay was used.

on packet PacketPlayOutOpenSignEditor:
  broadcast "%event-player%"
  broadcast "%event-packet%"
  cancel event

In this example, the player’s username and the packet name are displayed in the chat. And then cancel sending this event to the player.
The packet itself forces the player to open the text editing window of the plate.

Getting a buffer from a packet

After receiving the buffer from the packet, we can read the fields indicated on The Minecraft Wiki

buffer (of|from) %packet%
%packet%'s buffer

Reading the buffer

To get values from the buffer, the following expressions exist, similar to writing to the buffer

read bool[ean] from %bytebuf%
read uuid from %bytebuf%
read string from %bytebuf%
read position from %bytebuf%
read [unsigned] byte from %bytebuf%
read [unsigned] short from %bytebuf%
read float from %bytebuf%
read double from %bytebuf%
read int[eger] from %bytebuf%
read long from %bytebuf%
read angle from %bytebuf%
read var[iable][ ]int[eger] from %bytebuf%
read var[iable][ ]long from %bytebuf%
read utf[(-| )]8 [with [len[gth]]] %number% from %bytebuf%

To read utf-8 you must also specify the length of the text in bytes

Reading occurs in the same order as writing a packet, provided that the packet was not created by you.
If you created a packet and want to read it, then move its reader index to position zero.

In this tutorial, we will use the Open Sign Editor packet. Let’s see how we can read and use it.

Packet IDStateBound ToField NameField TypeNotes
0x32PlayClientLocationPosition
Is Front TextBooleanWhether the opened editor is for the front or on the back of the sign

Now, let’s use the information from this table to create the packet handling code.

First, let’s find the %packet name%.
To get the packet name, we can use the packet name finder ( See Packet Creation )

Second, we need to get the buffer from the packet.
To get the buffer, we can use the expression buffer (of|from) %packet% ( See Getting a buffer from a packet )

Third, let’s read the fields from the buffer.
To read a field, we can use the expression read %field type% from %buffer% ( See Reading the buffer )

Fourth, let’s use the information from the packet.
In this example, we will display the coordinates of the opened sign in the chat.

on packet PacketPlayOutOpenSignEditor:
  set {_buffer} to buffer from event-packet
  set {_position} to read position from {_buffer}
  set {_isFrontText} to read boolean from {_buffer}
  broadcast "%{_position}%"
  cancel event

And that’s it!
We have successfully read the packet and used it.

Tutorial written by @GuavaDealer

Reader index

Each reading of the buffer shifts its Reader index, this is the number of bytes read inside the buffer.
Reader index you can find out or change it using the following expression:

reader index of %bytebuf%
%bytebuf%'s reader index

Disabling or enabling packet handling

You can enable or disable handling of incoming or outgoing packets per player using the following expression.

[(handl(e|ing))|(listen[ing] [of])] (in|out)coming packets of %player%
%player%'s [(handl(e|ing))|(listen[ing] [of])] (in|out)coming packets
on join:
  set handling of incoming packets of player to false

Packet Extras

Get an Entity’s packet ID

This is different from a UUID, an entity ID is used to identify the entity in packets.
As such, they return different values.

entity id of %entity%
%entity%'s entity id

Manipulate a player’s skin value

skin value of %player%
%player%'s skin value

Manipulate a player’s skin signature

skin signature of %player%
%player%'s skin signature

Clear player’s skin signature and value

delete skin properties of %player%
delete %player%'s skin properties

Get text bytes

Returns a list of bytes.
It is also possible to specify the required encoding. Default is UTF-8

bytes of %string% [with charset %string%]
%string%'s bytes [with charset %string%]

Create Bundle packet

This is a packet that allows you to create a sequence of packets and send them to the client at once, which provides greater speed and stability.
If you are sending many packets at once, put them in a Bundle.

bundle packet (from|of|with) %packets%