From 688f13e649b567c38285ef09ba955d70f5e2c37e Mon Sep 17 00:00:00 2001 From: dongresource Date: Fri, 19 Mar 2021 22:28:25 +0100 Subject: [PATCH] [refactor] Implement generic, validating sendPacket() wrapper --- src/Groups.cpp | 8 + src/PlayerManager.hpp | 19 ++- src/core/CNProtocol.cpp | 29 +++- src/core/CNProtocol.hpp | 25 ++- src/core/CNStructs.hpp | 5 + src/core/Packets.cpp | 342 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 422 insertions(+), 6 deletions(-) diff --git a/src/Groups.cpp b/src/Groups.cpp index f38c0f8..ad3cff5 100644 --- a/src/Groups.cpp +++ b/src/Groups.cpp @@ -9,6 +9,14 @@ #include #include +/* + * NOTE: Variadic response packets that list group members are technically + * double-variadic, as they have two count members with trailing struct counts, + * and are thus incompatible with the generic sendPacket() wrapper. + * That means we still have to (carefully) use validOutVarPacket() in this + * source file. + */ + using namespace Groups; static void requestGroup(CNSocket* sock, CNPacketData* data) { diff --git a/src/PlayerManager.hpp b/src/PlayerManager.hpp index 616db50..c198baf 100644 --- a/src/PlayerManager.hpp +++ b/src/PlayerManager.hpp @@ -22,8 +22,6 @@ namespace PlayerManager { void sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I); void sendPlayerTo(CNSocket* sock, int X, int Y, int Z); - void sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size); - Player *getPlayer(CNSocket* key); std::string getPlayerName(Player *plr, bool id=true); @@ -33,4 +31,21 @@ namespace PlayerManager { CNSocket *getSockFromID(int32_t iID); CNSocket *getSockFromName(std::string firstname, std::string lastname); CNSocket *getSockFromAny(int by, int id, int uid, std::string firstname, std::string lastname); + + void sendToViewable(CNSocket *sock, void* buf, uint32_t type, size_t size); + + // TODO: unify this under the new Entity system + template + void sendToViewable(CNSocket *sock, T& pkt, uint32_t type) { + Player* plr = getPlayer(sock); + for (auto it = plr->viewableChunks->begin(); it != plr->viewableChunks->end(); it++) { + Chunk* chunk = *it; + for (CNSocket* otherSock : chunk->players) { + if (otherSock == sock) + continue; + + otherSock->sendPacket(pkt, type); + } + } + } } diff --git a/src/core/CNProtocol.cpp b/src/core/CNProtocol.cpp index eb80a41..f1b98d7 100644 --- a/src/core/CNProtocol.cpp +++ b/src/core/CNProtocol.cpp @@ -119,6 +119,28 @@ void CNSocket::kill() { #endif } +void CNSocket::validatingSendPacket(void *pkt, uint32_t packetType) { + assert(isOutboundPacketID(packetType)); + assert(Packets::packets.find(packetType) != Packets::packets.end()); + + PacketDesc& desc = Packets::packets[packetType]; + size_t resplen = desc.size; + + /* + * Note that this validation doesn't happen on time to prevent a buffer + * overflow if it would have taken place, but we do it anyway so the + * assertion failure at least makes it clear that something isn't being + * validated properly. + */ + if (desc.variadic) { + int32_t ntrailers = *(int32_t*)(((uint8_t*)pkt) + desc.cntMembOfs); + assert(validOutVarPacket(desc.size, ntrailers, desc.trailerSize)); + resplen = desc.size + ntrailers * desc.trailerSize; + } + + sendPacket(pkt, packetType, resplen); +} + void CNSocket::sendPacket(void* buf, uint32_t type, size_t size) { if (!alive) return; @@ -168,13 +190,18 @@ inline void CNSocket::parsePacket(uint8_t *buf, size_t size) { return; } + if (!isInboundPacketID(type)) { + std::cerr << "OpenFusion: UNEXPECTED PACKET: " << (int)type << std::endl; + return; + } + PacketDesc& desc = Packets::packets[type]; /* * Some packet structs with no meaningful contents have length 1, but * the client doesn't transmit that byte at all, so we special-case that. * It's important that we do that by zeroing that byte, as the server could - * bypothetically try and read from it and get a byte of the previous + * hypothetically try and read from it and get a byte of the previous * packet's contents. * * Assigning a zero byte to the body like this is safe, since there's a diff --git a/src/core/CNProtocol.hpp b/src/core/CNProtocol.hpp index f559a2d..ec50fa5 100644 --- a/src/core/CNProtocol.hpp +++ b/src/core/CNProtocol.hpp @@ -83,6 +83,14 @@ inline void* xmalloc(size_t sz) { return res; } +inline constexpr bool isInboundPacketID(uint32_t id) { + return ((id & CL2LS) == CL2LS) || ((id & CL2FE) == CL2FE); +} + +inline constexpr bool isOutboundPacketID(uint32_t id) { + return ((id & LS2CL) == LS2CL) || ((id & FE2CL) == FE2CL); +} + // overflow-safe validation of variable-length packets // for outbound packets inline constexpr bool validOutVarPacket(size_t base, int32_t npayloads, size_t plsize) { @@ -168,6 +176,7 @@ private: int recvData(buffer_t* data, int size); inline void parsePacket(uint8_t *buf, size_t size); + void validatingSendPacket(void *buf, uint32_t packetType); public: SOCKET sock; @@ -186,6 +195,16 @@ public: void sendPacket(void* buf, uint32_t packetType, size_t size); void step(); bool isAlive(); + + // generic, validating wrapper for sendPacket() + template + inline void sendPacket(T& pkt, uint32_t packetType) { + /* + * We do most of the logic in a helper, to lower the amount of code + * that gets generated multiple times with each template instantiation. + */ + validatingSendPacket((void*)&pkt, packetType); + } }; class CNServer; @@ -219,15 +238,15 @@ protected: bool active = true; + void addPollFD(SOCKET s); + void removePollFD(int i); + public: PacketHandler pHandler; CNServer(); CNServer(uint16_t p); - void addPollFD(SOCKET s); - void removePollFD(int i); - void start(); void kill(); static void printPacket(CNPacketData *data); diff --git a/src/core/CNStructs.hpp b/src/core/CNStructs.hpp index c9a30d1..b760ccd 100644 --- a/src/core/CNStructs.hpp +++ b/src/core/CNStructs.hpp @@ -28,6 +28,11 @@ #define INITSTRUCT(T, x) T x; \ memset(&x, 0, sizeof(T)); +#define INITVARPACKET(_buf, _Pkt, _pkt, _Trailer, _trailer) uint8_t _buf[CN_PACKET_BUFFER_SIZE]; \ + memset(&_buf, 0, CN_PACKET_BUFFER_SIZE); \ + auto _pkt = (_Pkt*)_buf; \ + auto _trailer = (_Trailer*)(_pkt + 1); + // macros to extract fields from instanceIDs #define MAPNUM(x) ((x) & 0xffffffff) #define PLAYERID(x) ((x) >> 32) diff --git a/src/core/Packets.cpp b/src/core/Packets.cpp index 8b850cf..0d0a431 100644 --- a/src/core/Packets.cpp +++ b/src/core/Packets.cpp @@ -5,8 +5,19 @@ #include "CNStructs.hpp" #define PACKET(id) {id, {id, sizeof(s##id), #id}} +#define MANUAL(id) {id, {id, sizeof(s##id), #id}} #define VAR_PACKET(id, memb, tr) {id, {id, sizeof(s##id), #id, offsetof(s##id, memb), sizeof(tr)}} +/* + * This map defines descriptors for all packets, and is used by the new system + * for validation. From now on, we have to convert new variadic packets from + * PACKET to VAR_PACKET in this list to use them. + * + * MANUAL is just a form of documentation stating that the packet is variadic + * and atypically encoded, so it won't be able to pass outbound validation and + * will need to be manually validated and sent using the legacy sendPacket() + * invocation pattern. + */ std::map Packets::packets = { // CL2LS PACKET(P_CL2LS_REQ_LOGIN), @@ -189,6 +200,337 @@ std::map Packets::packets = { PACKET(P_CL2FE_REQ_PC_DISASSEMBLE_ITEM), PACKET(P_CL2FE_GM_REQ_REWARD_RATE), PACKET(P_CL2FE_REQ_PC_ITEM_ENCHANT), + + // LS2CL + PACKET(P_LS2CL_REP_LOGIN_SUCC), + PACKET(P_LS2CL_REP_LOGIN_FAIL), + PACKET(P_LS2CL_REP_CHAR_INFO), + PACKET(P_LS2CL_REP_CHECK_CHAR_NAME_SUCC), + PACKET(P_LS2CL_REP_CHECK_CHAR_NAME_FAIL), + PACKET(P_LS2CL_REP_SAVE_CHAR_NAME_SUCC), + PACKET(P_LS2CL_REP_SAVE_CHAR_NAME_FAIL), + PACKET(P_LS2CL_REP_CHAR_CREATE_SUCC), + PACKET(P_LS2CL_REP_CHAR_CREATE_FAIL), + PACKET(P_LS2CL_REP_CHAR_SELECT_SUCC), + PACKET(P_LS2CL_REP_CHAR_SELECT_FAIL), + PACKET(P_LS2CL_REP_CHAR_DELETE_SUCC), + PACKET(P_LS2CL_REP_CHAR_DELETE_FAIL), + PACKET(P_LS2CL_REP_SHARD_SELECT_SUCC), + PACKET(P_LS2CL_REP_SHARD_SELECT_FAIL), + PACKET(P_LS2CL_REP_VERSION_CHECK_SUCC), + PACKET(P_LS2CL_REP_VERSION_CHECK_FAIL), + PACKET(P_LS2CL_REP_CHECK_NAME_LIST_SUCC), + PACKET(P_LS2CL_REP_CHECK_NAME_LIST_FAIL), + PACKET(P_LS2CL_REP_PC_EXIT_DUPLICATE), + PACKET(P_LS2CL_REQ_LIVE_CHECK), + PACKET(P_LS2CL_REP_CHANGE_CHAR_NAME_SUCC), + PACKET(P_LS2CL_REP_CHANGE_CHAR_NAME_FAIL), + PACKET(P_LS2CL_REP_SHARD_LIST_INFO_SUCC), + + // FE2CL + PACKET(P_FE2CL_ERROR), + PACKET(P_FE2CL_REP_PC_ENTER_FAIL), + PACKET(P_FE2CL_REP_PC_ENTER_SUCC), + PACKET(P_FE2CL_PC_NEW), + PACKET(P_FE2CL_REP_PC_EXIT_FAIL), + PACKET(P_FE2CL_REP_PC_EXIT_SUCC), + PACKET(P_FE2CL_PC_EXIT), + PACKET(P_FE2CL_PC_AROUND), + PACKET(P_FE2CL_PC_MOVE), + PACKET(P_FE2CL_PC_STOP), + PACKET(P_FE2CL_PC_JUMP), + PACKET(P_FE2CL_NPC_ENTER), + PACKET(P_FE2CL_NPC_EXIT), + PACKET(P_FE2CL_NPC_MOVE), + PACKET(P_FE2CL_NPC_NEW), + PACKET(P_FE2CL_NPC_AROUND), + PACKET(P_FE2CL_AROUND_DEL_PC), + PACKET(P_FE2CL_AROUND_DEL_NPC), + PACKET(P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_FREECHAT_MESSAGE_FAIL), + VAR_PACKET(P_FE2CL_PC_ATTACK_NPCs_SUCC, iNPCCnt, sAttackResult), + PACKET(P_FE2CL_PC_ATTACK_NPCs), + VAR_PACKET(P_FE2CL_NPC_ATTACK_PCs, iPCCnt, sAttackResult), + PACKET(P_FE2CL_REP_PC_REGEN_SUCC), + PACKET(P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_FAIL), + PACKET(P_FE2CL_PC_ITEM_MOVE_SUCC), + PACKET(P_FE2CL_PC_EQUIP_CHANGE), + PACKET(P_FE2CL_REP_PC_TASK_START_SUCC), + PACKET(P_FE2CL_REP_PC_TASK_START_FAIL), + PACKET(P_FE2CL_REP_PC_TASK_END_SUCC), + PACKET(P_FE2CL_REP_PC_TASK_END_FAIL), + PACKET(P_FE2CL_NPC_SKILL_READY), + PACKET(P_FE2CL_NPC_SKILL_FIRE), + MANUAL(P_FE2CL_NPC_SKILL_HIT), // variadic, trailer type depends on power + PACKET(P_FE2CL_NPC_SKILL_CORRUPTION_READY), + VAR_PACKET(P_FE2CL_NPC_SKILL_CORRUPTION_HIT, iTargetCnt, sCAttackResult), + PACKET(P_FE2CL_NPC_SKILL_CANCEL), + PACKET(P_FE2CL_REP_NANO_EQUIP_SUCC), + PACKET(P_FE2CL_REP_NANO_UNEQUIP_SUCC), + PACKET(P_FE2CL_REP_NANO_ACTIVE_SUCC), + PACKET(P_FE2CL_REP_NANO_TUNE_SUCC), + PACKET(P_FE2CL_NANO_ACTIVE), + MANUAL(P_FE2CL_NANO_SKILL_USE_SUCC), // variadic, trailer type depends on power + PACKET(P_FE2CL_NANO_SKILL_USE), + PACKET(P_FE2CL_REP_PC_TASK_STOP_SUCC), + PACKET(P_FE2CL_REP_PC_TASK_STOP_FAIL), + PACKET(P_FE2CL_REP_PC_TASK_CONTINUE_SUCC), + PACKET(P_FE2CL_REP_PC_TASK_CONTINUE_FAIL), + PACKET(P_FE2CL_REP_PC_GOTO_SUCC), + PACKET(P_FE2CL_REP_CHARGE_NANO_STAMINA), + PACKET(P_FE2CL_REP_PC_TICK), + PACKET(P_FE2CL_REP_PC_KILL_QUEST_NPCs_SUCC), + PACKET(P_FE2CL_REP_PC_VENDOR_ITEM_BUY_SUCC), + PACKET(P_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL), + PACKET(P_FE2CL_REP_PC_VENDOR_ITEM_SELL_SUCC), + PACKET(P_FE2CL_REP_PC_VENDOR_ITEM_SELL_FAIL), + PACKET(P_FE2CL_REP_PC_ITEM_DELETE_SUCC), + PACKET(P_FE2CL_PC_ROCKET_STYLE_READY), + PACKET(P_FE2CL_REP_PC_ROCKET_STYLE_FIRE_SUCC), + PACKET(P_FE2CL_PC_ROCKET_STYLE_FIRE), + PACKET(P_FE2CL_PC_ROCKET_STYLE_HIT), + PACKET(P_FE2CL_PC_GRENADE_STYLE_READY), + PACKET(P_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC), + PACKET(P_FE2CL_PC_GRENADE_STYLE_FIRE), + VAR_PACKET(P_FE2CL_PC_GRENADE_STYLE_HIT, iTargetCnt, sAttackResult), + PACKET(P_FE2CL_REP_PC_TRADE_OFFER), + PACKET(P_FE2CL_REP_PC_TRADE_OFFER_CANCEL), + PACKET(P_FE2CL_REP_PC_TRADE_OFFER_SUCC), + PACKET(P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL), + PACKET(P_FE2CL_REP_PC_TRADE_OFFER_ABORT), + PACKET(P_FE2CL_REP_PC_TRADE_CONFIRM), + PACKET(P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL), + PACKET(P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT), + PACKET(P_FE2CL_REP_PC_TRADE_CONFIRM_SUCC), + PACKET(P_FE2CL_REP_PC_TRADE_CONFIRM_FAIL), + PACKET(P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC), + PACKET(P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_FAIL), + PACKET(P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC), + PACKET(P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_FAIL), + PACKET(P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC), + PACKET(P_FE2CL_REP_PC_TRADE_CASH_REGISTER_FAIL), + PACKET(P_FE2CL_REP_PC_TRADE_EMOTES_CHAT), + PACKET(P_FE2CL_REP_PC_NANO_CREATE_SUCC), + PACKET(P_FE2CL_REP_PC_NANO_CREATE_FAIL), + PACKET(P_FE2CL_REP_NANO_TUNE_FAIL), + PACKET(P_FE2CL_REP_PC_BANK_OPEN_SUCC), + PACKET(P_FE2CL_REP_PC_BANK_OPEN_FAIL), + PACKET(P_FE2CL_REP_PC_BANK_CLOSE_SUCC), + PACKET(P_FE2CL_REP_PC_BANK_CLOSE_FAIL), + PACKET(P_FE2CL_REP_PC_VENDOR_START_SUCC), + PACKET(P_FE2CL_REP_PC_VENDOR_START_FAIL), + PACKET(P_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_SUCC), + PACKET(P_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_FAIL), + PACKET(P_FE2CL_REP_PC_VENDOR_ITEM_RESTORE_BUY_SUCC), + PACKET(P_FE2CL_REP_PC_VENDOR_ITEM_RESTORE_BUY_FAIL), + PACKET(P_FE2CL_CHAR_TIME_BUFF_TIME_OUT), + PACKET(P_FE2CL_REP_PC_GIVE_ITEM_SUCC), + PACKET(P_FE2CL_REP_PC_GIVE_ITEM_FAIL), + VAR_PACKET(P_FE2CL_REP_PC_BUDDYLIST_INFO_SUCC, iBuddyCnt, sBuddyBaseInfo), + PACKET(P_FE2CL_REP_PC_BUDDYLIST_INFO_FAIL), + PACKET(P_FE2CL_REP_REQUEST_MAKE_BUDDY_SUCC), + PACKET(P_FE2CL_REP_REQUEST_MAKE_BUDDY_FAIL), + PACKET(P_FE2CL_REP_ACCEPT_MAKE_BUDDY_SUCC), + PACKET(P_FE2CL_REP_ACCEPT_MAKE_BUDDY_FAIL), + PACKET(P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_FAIL), + PACKET(P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_FAIL), + PACKET(P_FE2CL_REP_GET_BUDDY_STYLE_SUCC), + PACKET(P_FE2CL_REP_GET_BUDDY_STYLE_FAIL), + PACKET(P_FE2CL_REP_GET_BUDDY_STATE_SUCC), + PACKET(P_FE2CL_REP_GET_BUDDY_STATE_FAIL), + PACKET(P_FE2CL_REP_SET_BUDDY_BLOCK_SUCC), + PACKET(P_FE2CL_REP_SET_BUDDY_BLOCK_FAIL), + PACKET(P_FE2CL_REP_REMOVE_BUDDY_SUCC), + PACKET(P_FE2CL_REP_REMOVE_BUDDY_FAIL), + PACKET(P_FE2CL_PC_JUMPPAD), + PACKET(P_FE2CL_PC_LAUNCHER), + PACKET(P_FE2CL_PC_ZIPLINE), + PACKET(P_FE2CL_PC_MOVEPLATFORM), + PACKET(P_FE2CL_PC_SLOPE), + PACKET(P_FE2CL_PC_STATE_CHANGE), + PACKET(P_FE2CL_REP_REQUEST_MAKE_BUDDY_SUCC_TO_ACCEPTER), + VAR_PACKET(P_FE2CL_REP_REWARD_ITEM, iItemCnt, sItemReward), + PACKET(P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC), + PACKET(P_FE2CL_REP_ITEM_CHEST_OPEN_FAIL), + MANUAL(P_FE2CL_CHAR_TIME_BUFF_TIME_TICK), // variadic, depends on skill type + PACKET(P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC), + PACKET(P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL), + PACKET(P_FE2CL_NPC_ROCKET_STYLE_FIRE), + PACKET(P_FE2CL_NPC_GRENADE_STYLE_FIRE), + PACKET(P_FE2CL_NPC_BULLET_STYLE_HIT), + PACKET(P_FE2CL_CHARACTER_ATTACK_CHARACTERs), + PACKET(P_FE2CL_PC_GROUP_INVITE), + PACKET(P_FE2CL_PC_GROUP_INVITE_FAIL), + PACKET(P_FE2CL_PC_GROUP_INVITE_REFUSE), + MANUAL(P_FE2CL_PC_GROUP_JOIN), // double-variadic, incompatible with this system + PACKET(P_FE2CL_PC_GROUP_JOIN_FAIL), + PACKET(P_FE2CL_PC_GROUP_JOIN_SUCC), // probably these ones too, but we don't use them anyway + MANUAL(P_FE2CL_PC_GROUP_LEAVE), // double-variadic, incompatible with this system + PACKET(P_FE2CL_PC_GROUP_LEAVE_FAIL), + PACKET(P_FE2CL_PC_GROUP_LEAVE_SUCC), // see GROUP_JOIN_SUCC + MANUAL(P_FE2CL_PC_GROUP_MEMBER_INFO), // double-variadic, incompatible with this system + PACKET(P_FE2CL_REP_PC_WARP_USE_NPC_SUCC), + PACKET(P_FE2CL_REP_PC_WARP_USE_NPC_FAIL), + PACKET(P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT), + PACKET(P_FE2CL_REP_PC_CHANGE_MENTOR_SUCC), + PACKET(P_FE2CL_REP_PC_CHANGE_MENTOR_FAIL), + PACKET(P_FE2CL_REP_GET_MEMBER_STYLE_FAIL), + PACKET(P_FE2CL_REP_GET_MEMBER_STYLE_SUCC), + PACKET(P_FE2CL_REP_GET_GROUP_STYLE_FAIL), + PACKET(P_FE2CL_REP_GET_GROUP_STYLE_SUCC), + PACKET(P_FE2CL_PC_REGEN), + PACKET(P_FE2CL_INSTANCE_MAP_INFO), + PACKET(P_FE2CL_TRANSPORTATION_ENTER), + PACKET(P_FE2CL_TRANSPORTATION_EXIT), + PACKET(P_FE2CL_TRANSPORTATION_MOVE), + PACKET(P_FE2CL_TRANSPORTATION_NEW), + PACKET(P_FE2CL_TRANSPORTATION_AROUND), + PACKET(P_FE2CL_AROUND_DEL_TRANSPORTATION), + PACKET(P_FE2CL_REP_EP_RANK_LIST), + PACKET(P_FE2CL_REP_EP_RANK_DETAIL), + PACKET(P_FE2CL_REP_EP_RANK_PC_INFO), + PACKET(P_FE2CL_REP_EP_RACE_START_SUCC), + PACKET(P_FE2CL_REP_EP_RACE_START_FAIL), + PACKET(P_FE2CL_REP_EP_RACE_END_SUCC), + PACKET(P_FE2CL_REP_EP_RACE_END_FAIL), + PACKET(P_FE2CL_REP_EP_RACE_CANCEL_SUCC), + PACKET(P_FE2CL_REP_EP_RACE_CANCEL_FAIL), + PACKET(P_FE2CL_REP_EP_GET_RING_SUCC), + PACKET(P_FE2CL_REP_EP_GET_RING_FAIL), + PACKET(P_FE2CL_REP_IM_CHANGE_SWITCH_STATUS), + PACKET(P_FE2CL_SHINY_ENTER), + PACKET(P_FE2CL_SHINY_EXIT), + PACKET(P_FE2CL_SHINY_NEW), + PACKET(P_FE2CL_SHINY_AROUND), + PACKET(P_FE2CL_AROUND_DEL_SHINY), + PACKET(P_FE2CL_REP_SHINY_PICKUP_FAIL), + PACKET(P_FE2CL_REP_SHINY_PICKUP_SUCC), + PACKET(P_FE2CL_PC_MOVETRANSPORTATION), + PACKET(P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_FAIL), + PACKET(P_FE2CL_REP_SEND_ANY_GROUP_FREECHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_ANY_GROUP_FREECHAT_MESSAGE_FAIL), + PACKET(P_FE2CL_REP_BARKER), + PACKET(P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_FAIL), + PACKET(P_FE2CL_REP_SEND_ANY_GROUP_MENUCHAT_MESSAGE_SUCC), + PACKET(P_FE2CL_REP_SEND_ANY_GROUP_MENUCHAT_MESSAGE_FAIL), + PACKET(P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL), + PACKET(P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC), + PACKET(P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_FAIL), + PACKET(P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC), + PACKET(P_FE2CL_ANNOUNCE_MSG), + PACKET(P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC), + PACKET(P_FE2CL_PC_SPECIAL_STATE_CHANGE), + PACKET(P_FE2CL_GM_REP_PC_SET_VALUE), + PACKET(P_FE2CL_GM_PC_CHANGE_VALUE), + PACKET(P_FE2CL_GM_REP_PC_LOCATION), + PACKET(P_FE2CL_GM_REP_PC_ANNOUNCE), + PACKET(P_FE2CL_REP_PC_BUDDY_WARP_FAIL), + PACKET(P_FE2CL_REP_PC_CHANGE_LEVEL), + PACKET(P_FE2CL_REP_SET_PC_BLOCK_SUCC), + PACKET(P_FE2CL_REP_SET_PC_BLOCK_FAIL), + PACKET(P_FE2CL_REP_REGIST_RXCOM), + PACKET(P_FE2CL_REP_REGIST_RXCOM_FAIL), + PACKET(P_FE2CL_PC_INVEN_FULL_MSG), + PACKET(P_FE2CL_REQ_LIVE_CHECK), + PACKET(P_FE2CL_PC_MOTD_LOGIN), + PACKET(P_FE2CL_REP_PC_ITEM_USE_FAIL), + VAR_PACKET(P_FE2CL_REP_PC_ITEM_USE_SUCC, iTargetCnt, sSkillResult_Buff), + PACKET(P_FE2CL_PC_ITEM_USE), + PACKET(P_FE2CL_REP_GET_BUDDY_LOCATION_SUCC), + PACKET(P_FE2CL_REP_GET_BUDDY_LOCATION_FAIL), + PACKET(P_FE2CL_REP_PC_RIDING_FAIL), + PACKET(P_FE2CL_REP_PC_RIDING_SUCC), + PACKET(P_FE2CL_PC_RIDING), + PACKET(P_FE2CL_PC_BROOMSTICK_MOVE), + PACKET(P_FE2CL_REP_PC_BUDDY_WARP_OTHER_SHARD_SUCC), + PACKET(P_FE2CL_REP_WARP_USE_RECALL_FAIL), + PACKET(P_FE2CL_REP_PC_EXIT_DUPLICATE), + PACKET(P_FE2CL_REP_PC_MISSION_COMPLETE_SUCC), + PACKET(P_FE2CL_PC_BUFF_UPDATE), + PACKET(P_FE2CL_REP_PC_NEW_EMAIL), + PACKET(P_FE2CL_REP_PC_READ_EMAIL_SUCC), + PACKET(P_FE2CL_REP_PC_READ_EMAIL_FAIL), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_PAGE_LIST_SUCC), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_PAGE_LIST_FAIL), + PACKET(P_FE2CL_REP_PC_DELETE_EMAIL_SUCC), + PACKET(P_FE2CL_REP_PC_DELETE_EMAIL_FAIL), + PACKET(P_FE2CL_REP_PC_SEND_EMAIL_SUCC), + PACKET(P_FE2CL_REP_PC_SEND_EMAIL_FAIL), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_ITEM_SUCC), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_ITEM_FAIL), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_CANDY_SUCC), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_CANDY_FAIL), + PACKET(P_FE2CL_PC_SUDDEN_DEAD), + PACKET(P_FE2CL_REP_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF_SUCC), + PACKET(P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID), + PACKET(P_FE2CL_REP_NPC_GROUP_INVITE_FAIL), + PACKET(P_FE2CL_REP_NPC_GROUP_INVITE_SUCC), + PACKET(P_FE2CL_REP_NPC_GROUP_KICK_FAIL), + PACKET(P_FE2CL_REP_NPC_GROUP_KICK_SUCC), + PACKET(P_FE2CL_PC_EVENT), + PACKET(P_FE2CL_REP_PC_TRANSPORT_WARP_SUCC), + PACKET(P_FE2CL_REP_PC_TRADE_EMOTES_CHAT_FAIL), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_ITEM_ALL_SUCC), + PACKET(P_FE2CL_REP_PC_RECV_EMAIL_ITEM_ALL_FAIL), + PACKET(P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC), + PACKET(P_FE2CL_REP_CHANNEL_INFO), + PACKET(P_FE2CL_REP_PC_CHANNEL_NUM), + PACKET(P_FE2CL_REP_PC_WARP_CHANNEL_FAIL), + PACKET(P_FE2CL_REP_PC_WARP_CHANNEL_SUCC), + PACKET(P_FE2CL_REP_PC_FIND_NAME_MAKE_BUDDY_SUCC), + PACKET(P_FE2CL_REP_PC_FIND_NAME_MAKE_BUDDY_FAIL), + PACKET(P_FE2CL_REP_PC_FIND_NAME_ACCEPT_BUDDY_FAIL), + PACKET(P_FE2CL_REP_PC_BUDDY_WARP_SAME_SHARD_SUCC), + VAR_PACKET(P_FE2CL_PC_ATTACK_CHARs_SUCC, iTargetCnt, sAttackResult), + VAR_PACKET(P_FE2CL_PC_ATTACK_CHARs, iTargetCnt, sAttackResult), + PACKET(P_FE2CL_NPC_ATTACK_CHARs), + PACKET(P_FE2CL_REP_PC_CHANGE_LEVEL_SUCC), + PACKET(P_FE2CL_REP_PC_NANO_CREATE), + PACKET(P_FE2CL_PC_STREETSTALL_REP_READY_SUCC), + PACKET(P_FE2CL_PC_STREETSTALL_REP_READY_FAIL), + PACKET(P_FE2CL_PC_STREETSTALL_REP_CANCEL_SUCC), + PACKET(P_FE2CL_PC_STREETSTALL_REP_CANCEL_FAIL), + PACKET(P_FE2CL_PC_STREETSTALL_REP_REGIST_ITEM_SUCC), + PACKET(P_FE2CL_PC_STREETSTALL_REP_REGIST_ITEM_FAIL), + PACKET(P_FE2CL_PC_STREETSTALL_REP_UNREGIST_ITEM_SUCC), + PACKET(P_FE2CL_PC_STREETSTALL_REP_UNREGIST_ITEM_FAIL), + PACKET(P_FE2CL_PC_STREETSTALL_REP_SALE_START_SUCC), + PACKET(P_FE2CL_PC_STREETSTALL_REP_SALE_START_FAIL), + PACKET(P_FE2CL_PC_STREETSTALL_REP_ITEM_LIST), + PACKET(P_FE2CL_PC_STREETSTALL_REP_ITEM_LIST_FAIL), + PACKET(P_FE2CL_PC_STREETSTALL_REP_ITEM_BUY_SUCC_BUYER), + PACKET(P_FE2CL_PC_STREETSTALL_REP_ITEM_BUY_SUCC_SELLER), + PACKET(P_FE2CL_PC_STREETSTALL_REP_ITEM_BUY_FAIL), + PACKET(P_FE2CL_REP_PC_ITEM_COMBINATION_SUCC), + PACKET(P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL), + PACKET(P_FE2CL_PC_CASH_BUFF_UPDATE), + PACKET(P_FE2CL_REP_PC_SKILL_ADD_SUCC), + PACKET(P_FE2CL_REP_PC_SKILL_ADD_FAIL), + PACKET(P_FE2CL_REP_PC_SKILL_DEL_SUCC), + PACKET(P_FE2CL_REP_PC_SKILL_DEL_FAIL), + PACKET(P_FE2CL_REP_PC_SKILL_USE_SUCC), + PACKET(P_FE2CL_REP_PC_SKILL_USE_FAIL), + PACKET(P_FE2CL_PC_SKILL_USE), + PACKET(P_FE2CL_PC_ROPE), + PACKET(P_FE2CL_PC_BELT), + PACKET(P_FE2CL_PC_VEHICLE_ON_SUCC), + PACKET(P_FE2CL_PC_VEHICLE_ON_FAIL), + PACKET(P_FE2CL_PC_VEHICLE_OFF_SUCC), + PACKET(P_FE2CL_PC_VEHICLE_OFF_FAIL), + PACKET(P_FE2CL_PC_QUICK_SLOT_INFO), + PACKET(P_FE2CL_REP_PC_REGIST_QUICK_SLOT_FAIL), + PACKET(P_FE2CL_REP_PC_REGIST_QUICK_SLOT_SUCC), + VAR_PACKET(P_FE2CL_PC_DELETE_TIME_LIMIT_ITEM, iItemListCount, sTimeLimitItemDeleteInfo2CL), + PACKET(P_FE2CL_REP_PC_DISASSEMBLE_ITEM_SUCC), + PACKET(P_FE2CL_REP_PC_DISASSEMBLE_ITEM_FAIL), + PACKET(P_FE2CL_GM_REP_REWARD_RATE_SUCC), + PACKET(P_FE2CL_REP_PC_ITEM_ENCHANT_SUCC), + PACKET(P_FE2CL_REP_PC_ITEM_ENCHANT_FAIL), }; std::string Packets::p2str(int val) {