Difference between revisions of "How to Write a Client"

From wiki.vg
Jump to navigation Jump to search
(43 intermediate revisions by 9 users not shown)
Line 1: Line 1:
This tutorial is being created to document what it takes to write a stand-alone client to interact with a notchian server (version Beta 1.2_01). The tutorial is incomplete but will be updated whenever more information is discovered.
+
This tutorial is being created to document what it takes to write a stand-alone client to interact with a notchian server. The tutorial is incomplete but will be updated whenever more information is discovered.
 +
 
 +
'''Note that a lot of the information here is out of date (< Apr 2013). Check [http://wiki.vg/index.php?title=How_to_Write_a_Client&action=history the page history] for what was recently updated.'''
  
 
== Before You Get Started ==
 
== Before You Get Started ==
  
* Make sure you don't want to join or fork an existing project instead.
+
* Make sure you don't want to join or fork an [[Client_List|existing project]] instead.
 
* Ponder how much work it will be.
 
* Ponder how much work it will be.
 
* Download the latest official minecraft server and run it with authentication turned off. Bind it to localhost if you want.
 
* Download the latest official minecraft server and run it with authentication turned off. Bind it to localhost if you want.
Line 11: Line 13:
 
''Main article: [[Protocol]]''
 
''Main article: [[Protocol]]''
  
Sorry, but you have to be able to parse ''all'' the messages. Write all the message parsing code. If you don't, your client will effectively crash if the server sends you any message you can't parse.  
+
Your client must be able to ''handle'' all the messages, but not necessarily be able to parse all the data. It is possible to skip packets that you're not interested in. Since the length of the packet is transmitted at the beginning of every packet (see [[Protocol#Packet_format|Packet Format]]), your client can simply skip the correct number of bytes to stay in sync. You ''will'' need libraries to do encryption (openssl or crypto) and compression (zlib).
  
 
== Login ==
 
== Login ==
Line 19: Line 21:
 
''Main article: [[Protocol FAQ]]''
 
''Main article: [[Protocol FAQ]]''
  
Paraphrase (with no authentication): send a 0x02, get a 0x02, send a 0x01, get a 0x01. Then you'll eventually get a 0x0D, and that's when the game really begins.
+
Paraphrase (with no authentication and no encryption): send a 0x02, get a 0xFD, send a 0xCD, get a 0x01, get a 0x06. Then you'll eventually get a 0x0D, and that's when the game really begins.
 +
 
 +
Paraphrase (with no authentication): send a 0x02, get a 0xFD, send a 0xFC, get a 0xFC (Then enable AES encrpytion), get a 0x01, get a 0x06. Then you'll eventually get a 0x0D, and that's when the game really begins.
  
 
To test if this worked, connect to your localhost server with the notchian client and see if you can see your custom client appear and float in the air.
 
To test if this worked, connect to your localhost server with the notchian client and see if you can see your custom client appear and float in the air.
Line 25: Line 29:
 
== Getting the map chunks ==
 
== Getting the map chunks ==
  
You have to convince the server that you deserve to know about all the map chunks that are around you.
+
Once you get your first 0x0D, you have to convince the server that you deserve to know about all the map chunks that are around you.
 +
The vanilla client will actually start sending 0x0D packets BEFORE receiving it's first 0x0D packet (while receiving 0x32 prechunks)
  
* Every 200 milliseconds, send one of 0x0A - 0x0D.
+
* Every 50 milliseconds, send one of 0x0A - 0x0D.
  
To test if this worked, count the number of 0x33 map chunk messages you get that are full-sized chunks (16,128,16). You should get hundreds.
+
You will get several fragments of chunks at first that are very far away from your location. Ignore these, since the chunks they are in will be loaded fully later. Full chunks load spiraling outward from your location in a circular (not square) pattern, eventually creating a 20x20 square for a total of 400 chunks.
  
If you're not doing it right, you might only see bits and pieces of the map loading really far away, or possibly just one chunk load where you're standing. It seems notchian servers send several partial chunks very far away from spawn when clients first log in. The chunks these fragments belong to will eventually be loaded completely, so it's probably safe to ignore the initial fragments.
+
To test if this worked, count the number of 0x33 map chunk messages you get that are full-sized chunks (16,128,16). If you don't get any, or you only get a couple, you probably aren't sending the 0x0A - 0x0D properly.
  
 
== Moving around ==
 
== Moving around ==
  
Send the server updates on your position (0x0A - 0x0D) every 200 milliseconds. This section was written experimenting with sending only 0x0D messages.
+
Send the server updates on your position (0x0A - 0x0D) at every 50 milliseconds. This section was written experimenting with sending only 0x0D messages. You can send position updates slower, but it causes health updates to be slower.
  
 
The server will mostly keep quiet about your position, which means that your movements are acceptable. If the server sends you your position, it means you've done something wrong. In this situation, you must apologize by sending back identical data or else the server will begin ignoring any future position updates. The jerking effect that happens in this event can be seen in notchian clients when trying to walk across missing chunks.
 
The server will mostly keep quiet about your position, which means that your movements are acceptable. If the server sends you your position, it means you've done something wrong. In this situation, you must apologize by sending back identical data or else the server will begin ignoring any future position updates. The jerking effect that happens in this event can be seen in notchian clients when trying to walk across missing chunks.
Line 43: Line 48:
 
=== Allowed super-human abilities ===
 
=== Allowed super-human abilities ===
  
* '''Flying''' - move about in the air. You must set on-ground to false to move vertically.
+
* '''Flying''' - float and move about in the air. You must set on-ground to false to move vertically. Gravity only exists if you say it exists. If the server has "allow-flight=false" on the configuration, after certain amount of time (5 seconds) the player will be kicked.
* '''Walking in the air''' - walk off a cliff with on-ground set to true. The avatar will continue walking as if there were ground bellow him.
+
* '''Walking in the air''' - walk off a cliff with on-ground set to true. The avatar will continue walking as if there were ground bellow him. Maybe the server doesn't even check any correlation between on-ground and proximity to the ground. Again, to do this the server needs to have flight enabled.
* '''Teleporting''' - put yourself anywhere instantly. Tested with a teleport distance of 1000m, which exceeds the bounds of the loaded map. Only tested with on-ground set to false.
+
*<s>'''Moving arbitrarily fast''' - update your position to move as far as you like with each step to move arbitrarily fast (as long as you have a clear path). Tested up to 1000m in a single step.</s> (this does not work anymore, gives a "Kicked for moving too fast. Hacking? :(" message.
* '''Moving arbitrarily fast''' - due to being able to teleport, simply update your position to move as far as you like with each step to move arbitrarily fast.
 
  
 
=== Restrictions ===
 
=== Restrictions ===
  
* You cannot move to inside of a solid block. Your bounding box is an apothem of 0.3m in the horizontal axises, and 1.74m from your feet to the top of your head.  
+
* You cannot intersect with solid blocks. Your bounding box is an apothem of 0.3m in the horizontal axises, and 1.74m from your feet to the top of your head.
* Sometimes moving super fast is not allowed. Most of the time it is allowed. It is unknown what exactly makes the server reject your motion.
+
* You cannot move through walls. If there are solid blocks in your way, you have to move around them no matter how fast you're going.
  
If you break any of the above rules, the server will send you your corrected position. Corrected positions preserve your on-ground status, even if you were trying to fall through the top of a solid block.
+
If you break any of the above rules, the server will send you your corrected position. Corrected positions preserve your on-ground status, even if you were trying to fall through the top of a solid block. Note that sometimes increasing the rate of position update messages will help the server follow along and not correct your position. 50 milliseconds seems to be a good update interval.
 
 
TODO: how to avoid the server console message "<username> moved wrongly!"
 
  
 
=== Look and Stance ===
 
=== Look and Stance ===
Line 61: Line 63:
 
Look is defined by yaw and pitch. Providing the yaw component to the server rotates your avatar's head about the vertical-axis. The notion of an avatar's body orientation seems to exist only in clients and updates automatically in notchian clients when players rotate their yaw and move around. Providing the pitch component rotates your avatar's head up and down. There seems to be no limit to the pitch, so providing a pitch of 180 degrees result in your avatar's head appearing upsidedown. See [[Protocol]] for how the yaw and pitch values are calibrated.
 
Look is defined by yaw and pitch. Providing the yaw component to the server rotates your avatar's head about the vertical-axis. The notion of an avatar's body orientation seems to exist only in clients and updates automatically in notchian clients when players rotate their yaw and move around. Providing the pitch component rotates your avatar's head up and down. There seems to be no limit to the pitch, so providing a pitch of 180 degrees result in your avatar's head appearing upsidedown. See [[Protocol]] for how the yaw and pitch values are calibrated.
  
Modifying your stance seems to have no visible effect. Its purpose is known.
+
Modifying your stance seems to have no visible effect. Its purpose is to modify the bounding box (for example, when the player is crouching it bounding box should be shorter)
  
 
=== Fall damage ===
 
=== Fall damage ===
Line 67: Line 69:
 
Fall damage happens when on-ground changes from false to true and the fall height is greater than some threshold around 4 meters. Fall height seems to be calculated by the difference between the point where on-ground changed to true and the highest point of the jump/fall/flight while on-ground was false.
 
Fall damage happens when on-ground changes from false to true and the fall height is greater than some threshold around 4 meters. Fall height seems to be calculated by the difference between the point where on-ground changed to true and the highest point of the jump/fall/flight while on-ground was false.
  
TODO: can you avoid fall damage while flying if you set on-ground to true in the air?
+
You can avoid fall damage if you fly at a slow constant speed (instead of constant acceleration) towards the floor.
  
 
=== Testing/Debugging ===
 
=== Testing/Debugging ===
Line 79: Line 81:
 
== Digging ==
 
== Digging ==
  
Requirements from the server to break a block
+
If you don't want to be able to abort digging:
* The dig modifier is '3'
+
 
* The distance from the players eyes to the block is less than 16
+
# send a start digging (0) packet and an finish digging (2) packet.
* For the server to process 0 and 1 modifiers, you must be within 6.0 of the center of the block you are mining
+
# server sends you an update block telling you of your success or failure after some amount of time has passed.
* Waiting between packets doesn't seem necessary (And can break digging. Conditions need verification)
+
 
* Face of the block is currently not validated and neither is where the player looks
+
If you do want to be able to abort digging:
  
=== To dig a block ===
+
# send a start digging (0).
 +
# wait appropriate amount of time (see below).
 +
# if you haven't aborted yet, send a finish digging (2).
  
{| class="wikitable"
+
If you go with the first option, you must wait until the block has been dug before you can start digging another block. In older versions of the server (1.4 and previous) you could bypass the time and destroy lots of blocks at once (instant mining) by sending "start digging" and "finish digging" packets without an interval in between.
|- class="row0"
 
| class="col0" | Optional arm animation
 
| class="col1" | [[Protocol#Animation_.280x12.29|0x12]], entity_id, 1
 
|- class="row1"
 
| class="col0 leftalign" | Start digging
 
| class="col1 centeralign" | [[Protocol#Player_Digging_.280x0E.29|0x0e]], 0, x, y, z, face
 
|- class="row2"
 
| class="col0 leftalign" | Dig (send multiple)
 
| class="col1 centeralign" | [[Protocol#Player_Digging_.280x0E.29|0x0e]], 1, x, y, z, face
 
|- class="row3"
 
| class="col0 leftalign" | Break block
 
| class="col1 centeralign" | [[Protocol#Player_Digging_.280x0E.29|0x0e]], 3, x, y, z, face
 
|- class="row4"
 
| class="col0 leftalign" | Stop digging
 
| class="col1 centeralign" | [[Protocol#Player_Digging_.280x0E.29|0x0e]], 2, 0, 0, 0, 0
 
|}
 
  
=== How many times do I have to dig? ===
+
=== How long to wait ===
 +
The server requires you to wait for a certain amount of time between sending a StartDiggingPacket and a StopDiggingPacket. Below is some old pseudocode; you can find an updated one [https://gist.github.com/phase/85d3081047cbf3d2f5ae here].
  
Dig counts varies with block type and equipped tool. The wrong tool will take damage while the right tool will lower the amount of digs required. Digging too many times doesn't seem to have a negative effect.
+
20 ticks per second
 +
 +
sum = 0
 +
every tick, sum += strengthVsBlock
 +
when sum >= 1.0, block is broken
 +
 +
function strengthVsBlock(tool, block, underwater, on_ground) {
 +
    if block.hardness < 0:
 +
        return 0
 +
    if not canHarvestBlock(tool, block):
 +
        return 1.0 / block.hardness / 100
 +
       
 +
    mult = 1
 +
   
 +
    if tool effective against block:
 +
        mult *= tool.effectiveness
 +
    if underwater:
 +
        mult /= 5
 +
    if not on_ground:
 +
        mult /= 5
 +
   
 +
    return mult / block.hardness / 30
 +
}
 +
 +
function canHarvestBlock(block) {
 +
 +
    if block material is not in (rock, iron, snow, snow_block):
 +
        return true
 +
    else
 +
        return whether equipped item can harvest block
 +
 +
}
 +
 +
effectiveness against proper material
 +
wood: 2.0
 +
stone: 4.0
 +
iron: 6.0
 +
diamond: 8.0
 +
gold: 12.0
 +
 +
 +
Shovel effective against:
 +
Block.grass, Block.dirt, Block.sand, Block.gravel, Block.snow, Block.blockSnow, Block.blockClay
 +
 +
 +
axe effective against:
 +
 +
Block.planks, Block.bookShelf, Block.wood, Block.crate
 +
 +
 +
pick effective against:
 +
            Block.cobblestone, Block.stairDouble, Block.stairSingle, Block.stone, Block.sandStone, Block.cobblestoneMossy, Block.oreIron, Block.blockSteel, Block.oreCoal, Block.blockGold,
 +
 +
            Block.oreGold, Block.oreDiamond, Block.blockDiamond, Block.ice, Block.bloodStone, Block.oreLapis, Block.blockLapis
 +
           
 +
pick can harvest:
 +
    switch(harvest level of tool):
 +
        case 3:
 +
            obsidian
 +
        case 2:
 +
            diamond
 +
            diamondore
 +
            gold
 +
            goldore
 +
            redstone
 +
            redstoneglowing
 +
        case 1:
 +
            iron
 +
            ironore
 +
            lapis
 +
            lapisore
 +
           
 +
    if block.material is rock
 +
        return true
 +
    if block.material is iron
 +
        return true
 +
   
 +
   
 +
    return false
 +
 +
shovel can harvest:
 +
    both types of snow = true
 +
    else false
 +
 +
axe can harvest:
 +
    false
 +
 +
 +
harvest level:
 +
wood: 0
 +
stone: 1
 +
iron: 2
 +
diamond: 3
 +
gold: 0
 +
 +
for the following fields, see https://github.com/PrismarineJS/minecraft-data/blob/master/data/1.8/blocks.json
 +
Block.hardness
 +
Block.material
  
'''NOTE:''' Needs verification. Empty handed dig requires many more than this.
+
=== Digging/Placing Blocks Behind Walls ===
 +
* Neither the Notchian server nor Bukkit check whether you actually have line-of-sight to a block when you dig or place blocks. Thus, if you noclip through a wall and mine the blocks behind it, the server will correct your position and ignore position updates, but still break those blocks which were within four meters of your corrected position. Likewise, any chests, buttons or levers can be used as long as they are within that critical 4-m distance.
  
'''NOTE:''' Holding a random block seems to require same amount of digs as empty hands.
+
== Inventory and Crafting ==
  
{| class="wikitable"
+
When you log in, before you get a 0x0D, you will get a [[Protocol#Window_Items|Window Items]] with all inventory slots including armor. You will then get a series of [[Protocol#Set_Slot|Set Slot]] repeating the slot information, one for every non-empty slot in the opened window, plus the cursor slot (which is empty by default, but changes when you click on a slot). The slot indexes of these messages are for an inventory window with the crafting zone empty.
|- class="row0"
 
! class="col0" | Block
 
! class="col2" | Empty hand
 
! class="col3" | Wood Shovel
 
|- class="row1"
 
| class="col0 leftalign" | Sand
 
| class="col2 centeralign" | <code>76</code>
 
| class="col3 centeralign" | <code>38</code>
 
|- class="row2"
 
| class="col0 leftalign" | Dirt
 
|- class="row3"
 
| class="col0 leftalign" | Stone
 
|- class="row4"
 
| class="col0 leftalign" | Wood
 
|}
 
  
=== Left to test ===
+
By clicking on a block or entity, the client can open a window. After sending the [[Protocol#Player_Block_Placement|Player Block Placement]] or [[Protocol#Use_Entity|Use Entity]] packet, the server responds with [[Protocol#Open_Window|Open Window]], [[Protocol#Window_Items|Window Items]], several [[Protocol#Set_Slot|Set Slot]] (one for every non-empty slot in the opened window, plus the cursor slot), and optionally [[Protocol#Window_Property|Window Property]]. It seems that only the most recently opened window can be interacted with. For more info, look at [[Inventory]].
* Can you dig behind blocks?
 
* Digging further than 6 blocks away
 
* Is tools enforced to drop blocks like stone?
 
* What happens to your tool if you dig too many times?
 
* Figure out tool modifiers to number of digs and verify dig counts on different blocks
 
  
== Placing/using stuff ==
+
Clicking happens by sending [[Protocol#Click_Window|Click Window]], which the server will answer with a [[Protocol#Confirm_Transaction|Confirm Transaction]]. If the "Clicked item" is wrong, the click will still be ''executed'' but not ''accepted''.
  
TODO: can you place blocks from behind walls?
+
If the click was not accepted by the server (accepted = false), the client must answer with [[Protocol#Confirm_Transaction_2|Confirm Transaction (serverbound)]] to apologize (like with movement), otherwise the server ignores any successive clicks. Additionally, the server answers erroneous clicks with one [[Protocol#Window_Items|Window Items]] and several [[Protocol#Set_Slot|Set Slot]] as above, to resynchronize the client with the server.
  
== Crafting ==
+
The client has to know all clicking behaviour (including crafting recipes) and change the slots accordingly after each click, because the server does not send any [[Protocol#Set_Slot|Set Slot]], just [[Protocol#Confirm_Transaction|Confirm Transaction]]. But you can cheat and always send the wrong "Clicked item" in [[Protocol#Click_Window|Click Window]] to force the server to send you all slots again while still applying your click.
  
TODO
+
Crafting is done by placing the correct materials into the crafting grid and clicking on the result slot (always slot nr. 0) to pick up the crafted item. Make sure to correctly update all slots after clicking the result slot, as some recipes (e.g. cake) leave back items in the crafting grid/inventory (e.g. empty buckets).
  
 
== Attacking mobs/players ==
 
== Attacking mobs/players ==
  
TODO
+
To attack another player or mob, send a 0x07 with the entity's id. The range seems to be limited to 4 meters or so and there must be a clear line of sight. If these conditions are not met, nothings happens. Damage is calculated on the server side.
  
 
== Chat ==
 
== Chat ==
Line 156: Line 223:
 
== Health and Respawning ==
 
== Health and Respawning ==
  
The server sends 0x08 health updates whenever your health changes. If the server sends a health value less than 1, you are dead. Your avatar will disappear a second or two after dying. The "fall over" animation is not automatic.
+
The server sends [[protocol#0x08|0x08 Health updates]] whenever your health changes. If the server sends a health value less than 1, you are dead. Your avatar will disappear a second or two after dying only if you keep sending position updates (packets 0x0A through 0x0D). The "fall over" animation is not automatic.
  
You can safely send a 0x09 Respawn immediately after you get a death notice. You'll be given a 0x0D and possibly other messages after you do.
+
After you get a death notice, you must still update your position while being dead. (Otherwise your dead body will be visible by notchian clients of the server, and you will be invisible after respawning.) Then, you can send a [[protocol#0xCD|0xCD Client Status]] to respawn. You'll be given a 0x0D with your new position, and possibly other messages.
  
TODO: why do health updates come so slowly sometimes? Damage from fire and healing from peaceful mode can be about 1/3 the speed of a notchian client.
+
If your health updates come much slower than on the notchian client, make sure you are sending position updates fast enough.

Revision as of 09:39, 16 August 2016

This tutorial is being created to document what it takes to write a stand-alone client to interact with a notchian server. The tutorial is incomplete but will be updated whenever more information is discovered.

Note that a lot of the information here is out of date (< Apr 2013). Check the page history for what was recently updated.

Before You Get Started

  • Make sure you don't want to join or fork an existing project instead.
  • Ponder how much work it will be.
  • Download the latest official minecraft server and run it with authentication turned off. Bind it to localhost if you want.

Parsing the messages

Main article: Protocol

Your client must be able to handle all the messages, but not necessarily be able to parse all the data. It is possible to skip packets that you're not interested in. Since the length of the packet is transmitted at the beginning of every packet (see Packet Format), your client can simply skip the correct number of bytes to stay in sync. You will need libraries to do encryption (openssl or crypto) and compression (zlib).

Login

Connect to the server at localhost, port 25565.

Main article: Protocol FAQ

Paraphrase (with no authentication and no encryption): send a 0x02, get a 0xFD, send a 0xCD, get a 0x01, get a 0x06. Then you'll eventually get a 0x0D, and that's when the game really begins.

Paraphrase (with no authentication): send a 0x02, get a 0xFD, send a 0xFC, get a 0xFC (Then enable AES encrpytion), get a 0x01, get a 0x06. Then you'll eventually get a 0x0D, and that's when the game really begins.

To test if this worked, connect to your localhost server with the notchian client and see if you can see your custom client appear and float in the air.

Getting the map chunks

Once you get your first 0x0D, you have to convince the server that you deserve to know about all the map chunks that are around you. The vanilla client will actually start sending 0x0D packets BEFORE receiving it's first 0x0D packet (while receiving 0x32 prechunks)

  • Every 50 milliseconds, send one of 0x0A - 0x0D.

You will get several fragments of chunks at first that are very far away from your location. Ignore these, since the chunks they are in will be loaded fully later. Full chunks load spiraling outward from your location in a circular (not square) pattern, eventually creating a 20x20 square for a total of 400 chunks.

To test if this worked, count the number of 0x33 map chunk messages you get that are full-sized chunks (16,128,16). If you don't get any, or you only get a couple, you probably aren't sending the 0x0A - 0x0D properly.

Moving around

Send the server updates on your position (0x0A - 0x0D) at every 50 milliseconds. This section was written experimenting with sending only 0x0D messages. You can send position updates slower, but it causes health updates to be slower.

The server will mostly keep quiet about your position, which means that your movements are acceptable. If the server sends you your position, it means you've done something wrong. In this situation, you must apologize by sending back identical data or else the server will begin ignoring any future position updates. The jerking effect that happens in this event can be seen in notchian clients when trying to walk across missing chunks.

The walking animation is automatically displayed in notchian clients when you move around on the ground. There's no walking animation when you move straight up and down though.

Allowed super-human abilities

  • Flying - float and move about in the air. You must set on-ground to false to move vertically. Gravity only exists if you say it exists. If the server has "allow-flight=false" on the configuration, after certain amount of time (5 seconds) the player will be kicked.
  • Walking in the air - walk off a cliff with on-ground set to true. The avatar will continue walking as if there were ground bellow him. Maybe the server doesn't even check any correlation between on-ground and proximity to the ground. Again, to do this the server needs to have flight enabled.
  • Moving arbitrarily fast - update your position to move as far as you like with each step to move arbitrarily fast (as long as you have a clear path). Tested up to 1000m in a single step. (this does not work anymore, gives a "Kicked for moving too fast. Hacking? :(" message.

Restrictions

  • You cannot intersect with solid blocks. Your bounding box is an apothem of 0.3m in the horizontal axises, and 1.74m from your feet to the top of your head.
  • You cannot move through walls. If there are solid blocks in your way, you have to move around them no matter how fast you're going.

If you break any of the above rules, the server will send you your corrected position. Corrected positions preserve your on-ground status, even if you were trying to fall through the top of a solid block. Note that sometimes increasing the rate of position update messages will help the server follow along and not correct your position. 50 milliseconds seems to be a good update interval.

Look and Stance

Look is defined by yaw and pitch. Providing the yaw component to the server rotates your avatar's head about the vertical-axis. The notion of an avatar's body orientation seems to exist only in clients and updates automatically in notchian clients when players rotate their yaw and move around. Providing the pitch component rotates your avatar's head up and down. There seems to be no limit to the pitch, so providing a pitch of 180 degrees result in your avatar's head appearing upsidedown. See Protocol for how the yaw and pitch values are calibrated.

Modifying your stance seems to have no visible effect. Its purpose is to modify the bounding box (for example, when the player is crouching it bounding box should be shorter)

Fall damage

Fall damage happens when on-ground changes from false to true and the fall height is greater than some threshold around 4 meters. Fall height seems to be calculated by the difference between the point where on-ground changed to true and the highest point of the jump/fall/flight while on-ground was false.

You can avoid fall damage if you fly at a slow constant speed (instead of constant acceleration) towards the floor.

Testing/Debugging

To test if moving around is working, watch your avatar move around from a notchian client.

If your avatar remains still despite your position update messages, then maybe you didn't apologize in response to the server correcting your position. Reconnect to give yourself another chance.

If your avatar is invisible to notchian clients despite the server sending you reasonable spawn coordinates, then maybe you died. Watch for 0x08 health updates to verify this cause. Try respawning or deleting the server's player file (world/players/<username>.dat) to recover from this situation.

Digging

If you don't want to be able to abort digging:

  1. send a start digging (0) packet and an finish digging (2) packet.
  2. server sends you an update block telling you of your success or failure after some amount of time has passed.

If you do want to be able to abort digging:

  1. send a start digging (0).
  2. wait appropriate amount of time (see below).
  3. if you haven't aborted yet, send a finish digging (2).

If you go with the first option, you must wait until the block has been dug before you can start digging another block. In older versions of the server (1.4 and previous) you could bypass the time and destroy lots of blocks at once (instant mining) by sending "start digging" and "finish digging" packets without an interval in between.

How long to wait

The server requires you to wait for a certain amount of time between sending a StartDiggingPacket and a StopDiggingPacket. Below is some old pseudocode; you can find an updated one here.

20 ticks per second

sum = 0
every tick, sum += strengthVsBlock
when sum >= 1.0, block is broken

function strengthVsBlock(tool, block, underwater, on_ground) {
    if block.hardness < 0:
        return 0
    if not canHarvestBlock(tool, block):
        return 1.0 / block.hardness / 100
        
    mult = 1
    
    if tool effective against block:
        mult *= tool.effectiveness
    if underwater:
        mult /= 5
    if not on_ground:
        mult /= 5
    
    return mult / block.hardness / 30
}

function canHarvestBlock(block) {

    if block material is not in (rock, iron, snow, snow_block):
        return true
    else
        return whether equipped item can harvest block

}

effectiveness against proper material
wood: 2.0
stone: 4.0
iron: 6.0
diamond: 8.0
gold: 12.0


Shovel effective against:
Block.grass, Block.dirt, Block.sand, Block.gravel, Block.snow, Block.blockSnow, Block.blockClay


axe effective against:

Block.planks, Block.bookShelf, Block.wood, Block.crate


pick effective against:
            Block.cobblestone, Block.stairDouble, Block.stairSingle, Block.stone, Block.sandStone, Block.cobblestoneMossy, Block.oreIron, Block.blockSteel, Block.oreCoal, Block.blockGold, 

            Block.oreGold, Block.oreDiamond, Block.blockDiamond, Block.ice, Block.bloodStone, Block.oreLapis, Block.blockLapis
            
pick can harvest:
    switch(harvest level of tool):
        case 3:
            obsidian
        case 2:
            diamond
            diamondore
            gold
            goldore
            redstone
            redstoneglowing
        case 1:
            iron
            ironore
            lapis
            lapisore
            
    if block.material is rock
        return true
    if block.material is iron
        return true
    
    
    return false

shovel can harvest:
    both types of snow = true
    else false

axe can harvest:
    false


harvest level:
wood: 0
stone: 1
iron: 2
diamond: 3
gold: 0

for the following fields, see https://github.com/PrismarineJS/minecraft-data/blob/master/data/1.8/blocks.json
Block.hardness
Block.material

Digging/Placing Blocks Behind Walls

  • Neither the Notchian server nor Bukkit check whether you actually have line-of-sight to a block when you dig or place blocks. Thus, if you noclip through a wall and mine the blocks behind it, the server will correct your position and ignore position updates, but still break those blocks which were within four meters of your corrected position. Likewise, any chests, buttons or levers can be used as long as they are within that critical 4-m distance.

Inventory and Crafting

When you log in, before you get a 0x0D, you will get a Window Items with all inventory slots including armor. You will then get a series of Set Slot repeating the slot information, one for every non-empty slot in the opened window, plus the cursor slot (which is empty by default, but changes when you click on a slot). The slot indexes of these messages are for an inventory window with the crafting zone empty.

By clicking on a block or entity, the client can open a window. After sending the Player Block Placement or Use Entity packet, the server responds with Open Window, Window Items, several Set Slot (one for every non-empty slot in the opened window, plus the cursor slot), and optionally Window Property. It seems that only the most recently opened window can be interacted with. For more info, look at Inventory.

Clicking happens by sending Click Window, which the server will answer with a Confirm Transaction. If the "Clicked item" is wrong, the click will still be executed but not accepted.

If the click was not accepted by the server (accepted = false), the client must answer with Confirm Transaction (serverbound) to apologize (like with movement), otherwise the server ignores any successive clicks. Additionally, the server answers erroneous clicks with one Window Items and several Set Slot as above, to resynchronize the client with the server.

The client has to know all clicking behaviour (including crafting recipes) and change the slots accordingly after each click, because the server does not send any Set Slot, just Confirm Transaction. But you can cheat and always send the wrong "Clicked item" in Click Window to force the server to send you all slots again while still applying your click.

Crafting is done by placing the correct materials into the crafting grid and clicking on the result slot (always slot nr. 0) to pick up the crafted item. Make sure to correctly update all slots after clicking the result slot, as some recipes (e.g. cake) leave back items in the crafting grid/inventory (e.g. empty buckets).

Attacking mobs/players

To attack another player or mob, send a 0x07 with the entity's id. The range seems to be limited to 4 meters or so and there must be a clear line of sight. If these conditions are not met, nothings happens. Damage is calculated on the server side.

Chat

Main article: Chat

Health and Respawning

The server sends 0x08 Health updates whenever your health changes. If the server sends a health value less than 1, you are dead. Your avatar will disappear a second or two after dying only if you keep sending position updates (packets 0x0A through 0x0D). The "fall over" animation is not automatic.

After you get a death notice, you must still update your position while being dead. (Otherwise your dead body will be visible by notchian clients of the server, and you will be invisible after respawning.) Then, you can send a 0xCD Client Status to respawn. You'll be given a 0x0D with your new position, and possibly other messages.

If your health updates come much slower than on the notchian client, make sure you are sending position updates fast enough.