/* see LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #include #include /* 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); } }