cobble/src/packet.c

538 lines
29 KiB
C

/* see LICENSE file for copyright and license details. */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <rxi/log.h>
#include <cobble/connection.h>
#include <cobble/packet.h>
#include <cobble/packet_impl.h>
#include <cobble/protocol.h>
#include <cobble/util.h>
/* lookup table for PacketType to id */
static const int32_t packet_id_lookup[] = {
[HANDSHAKE_SERVER_HANDSHAKE] = 0x00,
[PLAY_CLIENT_SPAWN_OBJECT] = 0x00,
[PLAY_CLIENT_SPAWN_EXPERIENCE_ORB] = 0x01,
[PLAY_CLIENT_SPAWN_GLOBAL_ENTITY] = 0x02,
[PLAY_CLIENT_SPAWN_MOB] = 0x03,
[PLAY_CLIENT_SPAWN_PAINTING] = 0x04,
[PLAY_CLIENT_SPAWN_PLAYER] = 0x05,
[PLAY_CLIENT_ANIMATION] = 0x06,
[PLAY_CLIENT_STATISTICS] = 0x07,
[PLAY_CLIENT_BLOCK_BREAK_ANIMATION] = 0x08,
[PLAY_CLIENT_UPDATE_BLOCK_ENTITY] = 0x09,
[PLAY_CLIENT_BLOCK_ACTION] = 0x0a,
[PLAY_CLIENT_BLOCK_CHANGE] = 0x0b,
[PLAY_CLIENT_BOSS_BAR] = 0x0c,
[PLAY_CLIENT_SERVER_DIFFICULTY] = 0x0d,
[PLAY_CLIENT_CHAT_MESSAGE] = 0x0e,
[PLAY_CLIENT_MULTI_BLOCK_CHANGE] = 0x0f,
[PLAY_CLIENT_TAB_COMPLETE] = 0x10,
[PLAY_CLIENT_DECLARE_COMMANDS] = 0x11,
[PLAY_CLIENT_CONFIRM_TRANSACTION] = 0x12,
[PLAY_CLIENT_CLOSE_WINDOW] = 0x13,
[PLAY_CLIENT_WINDOW_ITEMS] = 0x14,
[PLAY_CLIENT_WINDOW_PROPERTY] = 0x15,
[PLAY_CLIENT_SET_SLOT] = 0x16,
[PLAY_CLIENT_SET_COOLDOWN] = 0x17,
[PLAY_CLIENT_PLUGIN_MESSAGE] = 0x18,
[PLAY_CLIENT_NAMED_SOUND_EFFECT] = 0x19,
[PLAY_CLIENT_DISCONNECT] = 0x1a,
[PLAY_CLIENT_ENTITY_STATUS] = 0x1b,
[PLAY_CLIENT_EXPLOSION] = 0x1c,
[PLAY_CLIENT_UNLOAD_CHUNK] = 0x1d,
[PLAY_CLIENT_CHANGE_GAME_STATE] = 0x1e,
[PLAY_CLIENT_OPEN_HORSE_WINDOW] = 0x1f,
[PLAY_CLIENT_KEEP_ALIVE] = 0x20,
[PLAY_CLIENT_CHUNK_DATA] = 0x21,
[PLAY_CLIENT_EFFECT] = 0x22,
[PLAY_CLIENT_PARTICLE] = 0x23,
[PLAY_CLIENT_UPDATE_LIGHT] = 0x24,
[PLAY_CLIENT_JOIN_GAME] = 0x25,
[PLAY_CLIENT_MAP_DATA] = 0x26,
[PLAY_CLIENT_TRADE_LIST] = 0x27,
[PLAY_CLIENT_ENTITY_RELATIVE_MOVE] = 0x28,
[PLAY_CLIENT_ENTITY_LOOK_AND_RELATIVE_MOVE] = 0x29,
[PLAY_CLIENT_ENTITY_LOOK] = 0x2a,
[PLAY_CLIENT_ENTITY] = 0x2b,
[PLAY_CLIENT_VEHICLE_MOVE] = 0x2c,
[PLAY_CLIENT_OPEN_BOOK] = 0x2d,
[PLAY_CLIENT_OPEN_WINDOW] = 0x2e,
[PLAY_CLIENT_OPEN_SIGN_EDITOR] = 0x2f,
[PLAY_CLIENT_CRAFT_RECIPE_RESPONSE] = 0x30,
[PLAY_CLIENT_PlAYER_ABILITIES] = 0x31,
[PLAY_CLIENT_COMBAT_EVENT] = 0x32,
[PLAY_CLIENT_PLAYER_INFO] = 0x33,
[PLAY_CLIENT_FACE_PLAYER] = 0x34,
[PLAY_CLIENT_PLAYER_POSITION_AND_LOOK] = 0x35,
[PLAY_CLIENT_UNLOCK_RECIPES] = 0x36,
[PLAY_CLIENT_DESTROY_ENTITIES] = 0x37,
[PLAY_CLIENT_REMOVE_ENTITY_EFFECT] = 0x38,
[PLAY_CLIENT_RESOURCE_PACK_SEND] = 0x39,
[PLAY_CLIENT_RESPAWN] = 0x3a,
[PLAY_CLIENT_ENTITY_HEAD_LOOK] = 0x3b,
[PLAY_CLIENT_SELECT_ADVANCEMENT_TAB] = 0x3c,
[PLAY_CLIENT_WORLD_BORDER] = 0x3d,
[PLAY_CLIENT_CAMERA] = 0x3e,
[PLAY_CLIENT_HELD_ITEM_CHANGE] = 0x3f,
[PLAY_CLIENT_UPDATE_VIEW_POSITION] = 0x40,
[PLAY_CLIENT_UPDATE_VIEW_DISTANCE] = 0x41,
[PLAY_CLIENT_DISPLAY_SCOREBOARD] = 0x42,
[PLAY_CLIENT_ENTITY_METADATA] = 0x43,
[PLAY_CLIENT_ATTACH_ENTITY] = 0x44,
[PLAY_CLIENT_ENTITY_VELOCITY] = 0x45,
[PLAY_CLIENT_ENTITY_EQUIPMENT] = 0x46,
[PLAY_CLIENT_SET_EXPERIENCE] = 0x47,
[PLAY_CLIENT_UPDATE_HEALTH] = 0x48,
[PLAY_CLIENT_SCOREBOARD_OBJECTIVE] = 0x49,
[PLAY_CLIENT_SET_PASSENGERS] = 0x4a,
[PLAY_CLIENT_TEAMS] = 0x4b,
[PLAY_CLIENT_UPDATE_SCORE] = 0x4c,
[PLAY_CLIENT_SPAWN_POSITION] = 0x4d,
[PLAY_CLIENT_TIME_UPDATE] = 0x4e,
[PLAY_CLIENT_TITLE] = 0x4f,
[PLAY_CLIENT_ENTITY_SOUND_EFFECT] = 0x50,
[PLAY_CLIENT_SOUND_EFFECT] = 0x51,
[PLAY_CLIENT_STOP_SOUND] = 0x52,
[PLAY_CLIENT_PLAYER_LIST_HEADER_AND_FOOTER] = 0x53,
[PLAY_CLIENT_NBT_QUERY_RESPONSE] = 0x54,
[PLAY_CLIENT_COLLECT_ITEM] = 0x55,
[PLAY_CLIENT_ENTITY_TELEPORT] = 0x56,
[PLAY_CLIENT_ADVANCEMENTS] = 0x57,
[PLAY_CLIENT_ENTITY_PROPERTIES] = 0x58,
[PLAY_CLIENT_ENTITY_EFFECT] = 0x59,
[PLAY_CLIENT_DECLARE_RECIPES] = 0x5a,
[PLAY_CLIENT_TAGS] = 0x5b,
[PLAY_CLIENT_ACKNOWLEDGE_PLAYER_DIGGING] = 0x5c,
[PLAY_SERVER_TELEPORT_CONFIRM] = 0x00,
[PLAY_SERVER_QUERY_BLOCK_NBT] = 0x01,
[PLAY_SERVER_SET_DIFFICULTY] = 0x02,
[PLAY_SERVER_CHAT_MESSAGE] = 0x03,
[PLAY_SERVER_CLIENT_STATUS] = 0x04,
[PLAY_SERVER_CLIENT_SETTINGS] = 0x05,
[PLAY_SERVER_TAB_COMPLETE] = 0x06,
[PLAY_SERVER_CONFIRM_TRANSACTION] = 0x07,
[PLAY_SERVER_CLICK_WINDOW_BUTTON] = 0x08,
[PLAY_SERVER_CLICK_WINDOW] = 0x09,
[PLAY_SERVER_CLOSE_WINDOW] = 0x0a,
[PLAY_SERVER_PLUGIN_MESSAGE] = 0x0b,
[PLAY_SERVER_EDIT_BOOK] = 0x0c,
[PLAY_SERVER_QUERY_ENTITY_NBT] = 0x0d,
[PLAY_SERVER_USE_ENTITY] = 0x0e,
[PLAY_SERVER_KEEP_ALIVE] = 0x0f,
[PLAY_SERVER_LOCK_DIFFICULTY] = 0x10,
[PLAY_SERVER_PLAYER_POSITION] = 0x11,
[PLAY_SERVER_PLAYER_POSITION_AND_LOOK] = 0x12,
[PLAY_SERVER_PLAYER_LOOK] = 0x13,
[PLAY_SERVER_PLAYER] = 0x14,
[PLAY_SERVER_VEHICLE_MOVE] = 0x15,
[PLAY_SERVER_STEER_BOAT] = 0x16,
[PLAY_SERVER_PICK_ITEM] = 0x17,
[PLAY_SERVER_CRAFT_RECIPE_REQUEST] = 0x18,
[PLAY_SERVER_PLAYER_ABILITIES] = 0x19,
[PLAY_SERVER_PLAYER_DIGGING] = 0x1a,
[PLAY_SERVER_ENTITY_ACTION] = 0x1b,
[PLAY_SERVER_STEER_VEHICLE] = 0x1c,
[PLAY_SERVER_RECIPE_BOOK_DATA] = 0x1d,
[PLAY_SERVER_NAME_ITEM] = 0x1e,
[PLAY_SERVER_RESOURCE_PACK_STATUS] = 0x1f,
[PLAY_SERVER_ADVANCEMENT_TAB] = 0x20,
[PLAY_SERVER_SELECT_TRADE] = 0x21,
[PLAY_SERVER_SET_BEACON_EFFECT] = 0x22,
[PLAY_SERVER_HELD_ITEM_CHANGE] = 0x23,
[PLAY_SERVER_UPDATE_COMMAND_BLOCK] = 0x24,
[PLAY_SERVER_UPDATE_COMMAND_BLOCK_MINECART] = 0x25,
[PLAY_SERVER_CREATIVE_INVENTORY_ACTION] = 0x26,
[PLAY_SERVER_UPDATE_JIGSAW_BLOCK] = 0x27,
[PLAY_SERVER_UPDATE_STRUCTURE_BLOCK] = 0x28,
[PLAY_SERVER_UPDATE_SIGN] = 0x29,
[PLAY_SERVER_ANIMATION] = 0x2a,
[PLAY_SERVER_SPECTATE] = 0x2b,
[PLAY_SERVER_PLAYER_BLOCK_PLACEMENT] = 0x2c,
[PLAY_SERVER_USE_ITEM] = 0x2d,
[STATUS_CLIENT_RESPONSE] = 0x00,
[STATUS_CLIENT_PONG] = 0x01,
[STATUS_SERVER_REQUEST] = 0x00,
[STATUS_SERVER_PING] = 0x01,
[LOGIN_CLIENT_DISCONNECT] = 0x00,
[LOGIN_CLIENT_ENCRYPTION_REQUEST] = 0x01,
[LOGIN_CLIENT_LOGIN_SUCCESS] = 0x02,
[LOGIN_CLIENT_SET_COMPRESSION] = 0x03,
[LOGIN_CLIENT_LOGIN_PLUGIN_REQUEST] = 0x04,
[LOGIN_SERVER_LOGIN_START] = 0x00,
[LOGIN_SERVER_ENCRYPTION_RESPONSE] = 0x01,
[LOGIN_SERVER_LOGIN_PLUGIN_RESPONSE] = 0x02
};
/* lookup table for id and state to packet_type. this is only used for reading, so only serverbound packets will be included */
static const enum packet_type packet_type_lookup[][4] = {
[0x00] = { [HANDSHAKE] = HANDSHAKE_SERVER_HANDSHAKE, [PLAY] = PLAY_SERVER_TELEPORT_CONFIRM, [STATUS] = STATUS_SERVER_REQUEST, [LOGIN] = LOGIN_SERVER_LOGIN_START },
[0x01] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_QUERY_BLOCK_NBT, [STATUS] = STATUS_SERVER_PING, [LOGIN] = LOGIN_SERVER_ENCRYPTION_RESPONSE },
[0x02] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_SET_DIFFICULTY, [STATUS] = INVALID, [LOGIN] = LOGIN_SERVER_LOGIN_PLUGIN_RESPONSE },
[0x03] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CHAT_MESSAGE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x04] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CLIENT_STATUS, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x05] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CLIENT_SETTINGS, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x06] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_TAB_COMPLETE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x07] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CONFIRM_TRANSACTION, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x08] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CLICK_WINDOW_BUTTON, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x09] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CLICK_WINDOW, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x0a] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CLOSE_WINDOW, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x0b] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLUGIN_MESSAGE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x0c] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_EDIT_BOOK, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x0d] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_QUERY_ENTITY_NBT, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x0e] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_USE_ENTITY, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x0f] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_KEEP_ALIVE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x10] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_LOCK_DIFFICULTY, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x11] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLAYER_POSITION, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x12] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLAYER_POSITION_AND_LOOK, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x13] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLAYER_LOOK, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x14] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLAYER, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x15] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_VEHICLE_MOVE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x16] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_STEER_BOAT, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x17] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PICK_ITEM, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x18] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CRAFT_RECIPE_REQUEST, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x19] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLAYER_ABILITIES, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x1a] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLAYER_DIGGING, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x1b] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_ENTITY_ACTION, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x1c] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_STEER_VEHICLE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x1d] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_RECIPE_BOOK_DATA, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x1e] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_NAME_ITEM, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x1f] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_RESOURCE_PACK_STATUS, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x20] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_ADVANCEMENT_TAB, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x21] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_SELECT_TRADE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x22] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_SET_BEACON_EFFECT, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x23] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_HELD_ITEM_CHANGE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x24] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_UPDATE_COMMAND_BLOCK, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x25] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_UPDATE_COMMAND_BLOCK_MINECART, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x26] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_CREATIVE_INVENTORY_ACTION, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x27] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_UPDATE_JIGSAW_BLOCK, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x28] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_UPDATE_STRUCTURE_BLOCK, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x29] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_UPDATE_SIGN, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x2a] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_ANIMATION, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x2b] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_SPECTATE, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x2c] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_PLAYER_BLOCK_PLACEMENT, [STATUS] = INVALID, [LOGIN] = INVALID },
[0x2d] = { [HANDSHAKE] = INVALID, [PLAY] = PLAY_SERVER_USE_ITEM, [STATUS] = INVALID, [LOGIN] = INVALID }
};
/* lookup table and storage struct for packet functions */
typedef struct {
bool (*read)(struct connection*, struct packet*, uint8_t *data, size_t data_len);
bool (*write)(struct connection*, struct packet*, uint8_t *buf, size_t buf_len);
size_t (*size)(struct packet*);
void (*destroy)(struct packet*);
void (*handle)(struct connection*, struct packet*);
} PacketFunctions;
static const PacketFunctions packet_function_lookup[] = {
[HANDSHAKE_SERVER_HANDSHAKE] = { packet_handshake_read,
NULL,
NULL,
packet_handshake_destroy,
packet_handshake_handle },
[PLAY_CLIENT_SPAWN_OBJECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SPAWN_EXPERIENCE_ORB] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SPAWN_GLOBAL_ENTITY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SPAWN_MOB] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SPAWN_PAINTING] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SPAWN_PLAYER] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ANIMATION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_STATISTICS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_BLOCK_BREAK_ANIMATION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UPDATE_BLOCK_ENTITY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_BLOCK_ACTION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_BLOCK_CHANGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_BOSS_BAR] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SERVER_DIFFICULTY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_CHAT_MESSAGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_MULTI_BLOCK_CHANGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_TAB_COMPLETE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_DECLARE_COMMANDS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_CONFIRM_TRANSACTION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_CLOSE_WINDOW] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_WINDOW_ITEMS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_WINDOW_PROPERTY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SET_SLOT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SET_COOLDOWN] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_PLUGIN_MESSAGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_NAMED_SOUND_EFFECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_DISCONNECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_STATUS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_EXPLOSION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UNLOAD_CHUNK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_CHANGE_GAME_STATE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_OPEN_HORSE_WINDOW] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_KEEP_ALIVE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_CHUNK_DATA] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_EFFECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_PARTICLE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UPDATE_LIGHT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_JOIN_GAME] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_MAP_DATA] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_TRADE_LIST] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_RELATIVE_MOVE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_LOOK_AND_RELATIVE_MOVE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_LOOK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_VEHICLE_MOVE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_OPEN_BOOK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_OPEN_WINDOW] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_OPEN_SIGN_EDITOR] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_CRAFT_RECIPE_RESPONSE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_PlAYER_ABILITIES] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_COMBAT_EVENT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_PLAYER_INFO] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_FACE_PLAYER] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_PLAYER_POSITION_AND_LOOK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UNLOCK_RECIPES] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_DESTROY_ENTITIES] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_REMOVE_ENTITY_EFFECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_RESOURCE_PACK_SEND] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_RESPAWN] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_HEAD_LOOK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SELECT_ADVANCEMENT_TAB] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_WORLD_BORDER] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_CAMERA] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_HELD_ITEM_CHANGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UPDATE_VIEW_POSITION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UPDATE_VIEW_DISTANCE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_DISPLAY_SCOREBOARD] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_METADATA] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ATTACH_ENTITY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_VELOCITY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_EQUIPMENT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SET_EXPERIENCE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UPDATE_HEALTH] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SCOREBOARD_OBJECTIVE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SET_PASSENGERS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_TEAMS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_UPDATE_SCORE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SPAWN_POSITION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_TIME_UPDATE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_TITLE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_SOUND_EFFECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_SOUND_EFFECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_STOP_SOUND] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_PLAYER_LIST_HEADER_AND_FOOTER] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_NBT_QUERY_RESPONSE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_COLLECT_ITEM] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_TELEPORT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ADVANCEMENTS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_PROPERTIES] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ENTITY_EFFECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_DECLARE_RECIPES] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_TAGS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_CLIENT_ACKNOWLEDGE_PLAYER_DIGGING] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_TELEPORT_CONFIRM] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_QUERY_BLOCK_NBT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_SET_DIFFICULTY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CHAT_MESSAGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CLIENT_STATUS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CLIENT_SETTINGS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_TAB_COMPLETE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CONFIRM_TRANSACTION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CLICK_WINDOW_BUTTON] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CLICK_WINDOW] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CLOSE_WINDOW] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLUGIN_MESSAGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_EDIT_BOOK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_QUERY_ENTITY_NBT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_USE_ENTITY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_KEEP_ALIVE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_LOCK_DIFFICULTY] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLAYER_POSITION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLAYER_POSITION_AND_LOOK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLAYER_LOOK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLAYER] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_VEHICLE_MOVE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_STEER_BOAT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PICK_ITEM] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CRAFT_RECIPE_REQUEST] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLAYER_ABILITIES] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLAYER_DIGGING] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_ENTITY_ACTION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_STEER_VEHICLE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_RECIPE_BOOK_DATA] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_NAME_ITEM] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_RESOURCE_PACK_STATUS] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_ADVANCEMENT_TAB] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_SELECT_TRADE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_SET_BEACON_EFFECT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_HELD_ITEM_CHANGE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_UPDATE_COMMAND_BLOCK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_UPDATE_COMMAND_BLOCK_MINECART] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_CREATIVE_INVENTORY_ACTION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_UPDATE_JIGSAW_BLOCK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_UPDATE_STRUCTURE_BLOCK] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_UPDATE_SIGN] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_ANIMATION] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_SPECTATE] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_PLAYER_BLOCK_PLACEMENT] = { NULL, NULL, NULL, NULL, NULL },
[PLAY_SERVER_USE_ITEM] = { NULL, NULL, NULL, NULL, NULL },
[STATUS_CLIENT_RESPONSE] = { NULL,
packet_response_write,
packet_response_size,
packet_response_destroy,
NULL },
[STATUS_CLIENT_PONG] = { NULL,
packet_pong_write,
packet_pong_size,
NULL,
NULL },
[STATUS_SERVER_REQUEST] = { packet_request_read,
NULL,
NULL,
NULL,
packet_request_handle },
[STATUS_SERVER_PING] = { packet_ping_read,
NULL,
NULL,
NULL,
packet_ping_handle },
[LOGIN_CLIENT_DISCONNECT] = { NULL, NULL, NULL, NULL, NULL },
[LOGIN_CLIENT_ENCRYPTION_REQUEST] = { NULL, NULL, NULL, NULL, NULL },
[LOGIN_CLIENT_LOGIN_SUCCESS] = { NULL,
packet_login_success_write,
packet_login_success_size,
packet_login_success_destroy,
NULL },
[LOGIN_CLIENT_SET_COMPRESSION] = { NULL, NULL, NULL, NULL, NULL },
[LOGIN_CLIENT_LOGIN_PLUGIN_REQUEST] = { NULL, NULL, NULL, NULL, NULL },
[LOGIN_SERVER_LOGIN_START] = { packet_login_start_read,
NULL,
NULL,
packet_login_start_destroy,
packet_login_start_handle },
[LOGIN_SERVER_ENCRYPTION_RESPONSE] = { NULL, NULL, NULL, NULL, NULL },
[LOGIN_SERVER_LOGIN_PLUGIN_RESPONSE] = { NULL, NULL, NULL, NULL, NULL }
};
struct packet*
packet_new(enum packet_type type, void *packet_data)
{
struct packet *packet;
packet = malloc(sizeof(struct packet));
packet->id = packet_id_lookup[type];
packet->type = type;
packet->data = packet_data;
return packet;
}
bool
packet_read(struct connection *conn, struct packet *packet, uint8_t *data, size_t data_len)
{
size_t id_size;
bool (*read_function)(struct connection*, struct packet*, uint8_t *data, size_t data_len);
id_size = read_varint(&packet->id, data, data_len);
log_debug("Reading packet with id %d", packet->id);
packet->type = packet_type_lookup[packet->id][conn->protocol_state];
if (packet->type == INVALID) {
log_warn("No packet type found for packet with id %d", packet->id);
return false;
}
read_function = packet_function_lookup[packet->type].read;
if (read_function == NULL) {
log_warn("No read function found for packet with id %d", packet->id);
return false;
}
if (!read_function(conn, packet, data + id_size, data_len - id_size)) {
log_warn("Failed read function for packet with id %d", packet->id);
return false;
}
return true;
}
bool
packet_write(struct connection *conn, struct packet *packet)
{
uint8_t *buf;
size_t p_size, buf_size, data_size, id_size, data_size_size;
bool (*write_function)(struct connection*, struct packet*, uint8_t *buf, size_t buf_len);
log_debug("Writing packet with id %d", packet->id);
p_size = packet_size(packet);
buf_size = p_size + 10;
buf = SAFE_MALLOC(buf_size);
buf += 10;
write_function = packet_function_lookup[packet->type].write;
if (write_function == NULL) {
log_warn("No write function found for packet with id %d", packet->id);
return false;
}
if (!write_function(conn, packet, buf, p_size)) {
log_warn("failed write function for packet with id %d", packet->id);
return false;
}
/* now that we have written the packet data to the buffer, we have to write the id and the data size.
* the order of the information in the buffer is {data_size} {id} {packet_data}.
* both the data_size and the id are stored as varints, hence the extra 10 bytes allocated at the beginning of the buffer.
* */
id_size = get_varint_len(packet->id);
write_varint(packet->id, buf - id_size);
data_size = id_size + p_size;
data_size_size = get_varint_len(data_size);
write_varint(data_size, buf - (id_size + data_size_size));
dyad_write(conn->dyad_stream, buf - (id_size + data_size_size), (data_size_size + data_size));
free(buf - 10);
return true;
}
size_t
packet_size(struct packet *packet)
{
size_t (*size_function)(struct packet*);
size_function = packet_function_lookup[packet->type].size;
if (size_function == NULL) {
log_warn("No size function found for packet with id %d", packet->id);
return -1;
}
return size_function(packet);
}
void
packet_destroy(struct packet *packet)
{
void (*destroy_function)(struct packet*);
destroy_function = packet_function_lookup[packet->type].destroy;
if (destroy_function == NULL) {
log_debug("No destroy function for packet with id %d", packet->id);
} else {
destroy_function(packet);
}
free(packet->data);
free(packet);
packet = NULL;
}
void
packet_handle(struct connection *conn, struct packet *packet)
{
void (*handle_function)(struct connection*, struct packet*);
handle_function = packet_function_lookup[packet->type].handle;
if (handle_function == NULL) {
log_debug("No handle function for packet with id %d", packet->id);
} else {
handle_function(conn, packet);
}
}