Files
Erupe/network/mhfpacket/msg_comprehensive_test.go
Houmgaor d27da5ec86 fix(items): stop G-rank Workshop/Cog softlock on missing ACK
MSG_MHF_GET_EXTRA_INFO (0xA6) and MSG_MHF_GET_COG_INFO (0xC3) had
Parse() returning NOT IMPLEMENTED. The dispatch loop treats any Parse
error as a hard drop — no ACK is ever sent, so the client waits
indefinitely and effectively soft-locks when entering the G-rank
Workshop or Master Felyne (Cog) screens.

Fix: parse AckHandle (the only field we can confirm from the protocol)
and respond with doAckBufFail so the client receives a well-formed
buf-type ACK with error code 1. The client's fail branch for these
requests exits cleanly without reading response fields, avoiding the
read-past-EOF crash that an empty success ACK would cause.

The full response format for both packets is still unknown; a complete
implementation requires further RE. The TODO comments mark the gap.

Fixes #180.
2026-03-19 14:35:38 +01:00

1154 lines
41 KiB
Go

package mhfpacket
import (
"io"
"testing"
"erupe-ce/common/byteframe"
cfg "erupe-ce/config"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// TestAllOpcodesFromOpcode verifies that FromOpcode returns non-nil packets for all known opcodes
func TestAllOpcodesFromOpcode(t *testing.T) {
// All opcodes from opcode_to_packet.go
opcodes := []network.PacketID{
network.MSG_HEAD,
network.MSG_SYS_reserve01,
network.MSG_SYS_reserve02,
network.MSG_SYS_reserve03,
network.MSG_SYS_reserve04,
network.MSG_SYS_reserve05,
network.MSG_SYS_reserve06,
network.MSG_SYS_reserve07,
network.MSG_SYS_ADD_OBJECT,
network.MSG_SYS_DEL_OBJECT,
network.MSG_SYS_DISP_OBJECT,
network.MSG_SYS_HIDE_OBJECT,
network.MSG_SYS_reserve0C,
network.MSG_SYS_reserve0D,
network.MSG_SYS_reserve0E,
network.MSG_SYS_EXTEND_THRESHOLD,
network.MSG_SYS_END,
network.MSG_SYS_NOP,
network.MSG_SYS_ACK,
network.MSG_SYS_TERMINAL_LOG,
network.MSG_SYS_LOGIN,
network.MSG_SYS_LOGOUT,
network.MSG_SYS_SET_STATUS,
network.MSG_SYS_PING,
network.MSG_SYS_CAST_BINARY,
network.MSG_SYS_HIDE_CLIENT,
network.MSG_SYS_TIME,
network.MSG_SYS_CASTED_BINARY,
network.MSG_SYS_GET_FILE,
network.MSG_SYS_ISSUE_LOGKEY,
network.MSG_SYS_RECORD_LOG,
network.MSG_SYS_ECHO,
network.MSG_SYS_CREATE_STAGE,
network.MSG_SYS_STAGE_DESTRUCT,
network.MSG_SYS_ENTER_STAGE,
network.MSG_SYS_BACK_STAGE,
network.MSG_SYS_MOVE_STAGE,
network.MSG_SYS_LEAVE_STAGE,
network.MSG_SYS_LOCK_STAGE,
network.MSG_SYS_UNLOCK_STAGE,
network.MSG_SYS_RESERVE_STAGE,
network.MSG_SYS_UNRESERVE_STAGE,
network.MSG_SYS_SET_STAGE_PASS,
network.MSG_SYS_WAIT_STAGE_BINARY,
network.MSG_SYS_SET_STAGE_BINARY,
network.MSG_SYS_GET_STAGE_BINARY,
network.MSG_SYS_ENUMERATE_CLIENT,
network.MSG_SYS_ENUMERATE_STAGE,
network.MSG_SYS_CREATE_MUTEX,
network.MSG_SYS_CREATE_OPEN_MUTEX,
network.MSG_SYS_DELETE_MUTEX,
network.MSG_SYS_OPEN_MUTEX,
network.MSG_SYS_CLOSE_MUTEX,
network.MSG_SYS_CREATE_SEMAPHORE,
network.MSG_SYS_CREATE_ACQUIRE_SEMAPHORE,
network.MSG_SYS_DELETE_SEMAPHORE,
network.MSG_SYS_ACQUIRE_SEMAPHORE,
network.MSG_SYS_RELEASE_SEMAPHORE,
network.MSG_SYS_LOCK_GLOBAL_SEMA,
network.MSG_SYS_UNLOCK_GLOBAL_SEMA,
network.MSG_SYS_CHECK_SEMAPHORE,
network.MSG_SYS_OPERATE_REGISTER,
network.MSG_SYS_LOAD_REGISTER,
network.MSG_SYS_NOTIFY_REGISTER,
network.MSG_SYS_CREATE_OBJECT,
network.MSG_SYS_DELETE_OBJECT,
network.MSG_SYS_POSITION_OBJECT,
network.MSG_SYS_ROTATE_OBJECT,
network.MSG_SYS_DUPLICATE_OBJECT,
network.MSG_SYS_SET_OBJECT_BINARY,
network.MSG_SYS_GET_OBJECT_BINARY,
network.MSG_SYS_GET_OBJECT_OWNER,
network.MSG_SYS_UPDATE_OBJECT_BINARY,
network.MSG_SYS_CLEANUP_OBJECT,
network.MSG_SYS_reserve4A,
network.MSG_SYS_reserve4B,
network.MSG_SYS_reserve4C,
network.MSG_SYS_reserve4D,
network.MSG_SYS_reserve4E,
network.MSG_SYS_reserve4F,
network.MSG_SYS_INSERT_USER,
network.MSG_SYS_DELETE_USER,
network.MSG_SYS_SET_USER_BINARY,
network.MSG_SYS_GET_USER_BINARY,
network.MSG_SYS_NOTIFY_USER_BINARY,
network.MSG_SYS_reserve55,
network.MSG_SYS_reserve56,
network.MSG_SYS_reserve57,
network.MSG_SYS_UPDATE_RIGHT,
network.MSG_SYS_AUTH_QUERY,
network.MSG_SYS_AUTH_DATA,
network.MSG_SYS_AUTH_TERMINAL,
network.MSG_SYS_reserve5C,
network.MSG_SYS_RIGHTS_RELOAD,
network.MSG_SYS_reserve5E,
network.MSG_SYS_reserve5F,
network.MSG_MHF_SAVEDATA,
network.MSG_MHF_LOADDATA,
network.MSG_MHF_LIST_MEMBER,
network.MSG_MHF_OPR_MEMBER,
network.MSG_MHF_ENUMERATE_DIST_ITEM,
network.MSG_MHF_APPLY_DIST_ITEM,
network.MSG_MHF_ACQUIRE_DIST_ITEM,
network.MSG_MHF_GET_DIST_DESCRIPTION,
network.MSG_MHF_SEND_MAIL,
network.MSG_MHF_READ_MAIL,
network.MSG_MHF_LIST_MAIL,
network.MSG_MHF_OPRT_MAIL,
network.MSG_MHF_LOAD_FAVORITE_QUEST,
network.MSG_MHF_SAVE_FAVORITE_QUEST,
network.MSG_MHF_REGISTER_EVENT,
network.MSG_MHF_RELEASE_EVENT,
network.MSG_MHF_TRANSIT_MESSAGE,
network.MSG_SYS_reserve71,
network.MSG_SYS_reserve72,
network.MSG_SYS_reserve73,
network.MSG_SYS_reserve74,
network.MSG_SYS_reserve75,
network.MSG_SYS_reserve76,
network.MSG_SYS_reserve77,
network.MSG_SYS_reserve78,
network.MSG_SYS_reserve79,
network.MSG_SYS_reserve7A,
network.MSG_SYS_reserve7B,
network.MSG_SYS_reserve7C,
network.MSG_CA_EXCHANGE_ITEM,
network.MSG_SYS_reserve7E,
network.MSG_MHF_PRESENT_BOX,
network.MSG_MHF_SERVER_COMMAND,
network.MSG_MHF_SHUT_CLIENT,
network.MSG_MHF_ANNOUNCE,
network.MSG_MHF_SET_LOGINWINDOW,
network.MSG_SYS_TRANS_BINARY,
network.MSG_SYS_COLLECT_BINARY,
network.MSG_SYS_GET_STATE,
network.MSG_SYS_SERIALIZE,
network.MSG_SYS_ENUMLOBBY,
network.MSG_SYS_ENUMUSER,
network.MSG_SYS_INFOKYSERVER,
network.MSG_MHF_GET_CA_UNIQUE_ID,
network.MSG_MHF_SET_CA_ACHIEVEMENT,
network.MSG_MHF_CARAVAN_MY_SCORE,
network.MSG_MHF_CARAVAN_RANKING,
network.MSG_MHF_CARAVAN_MY_RANK,
network.MSG_MHF_CREATE_GUILD,
network.MSG_MHF_OPERATE_GUILD,
network.MSG_MHF_OPERATE_GUILD_MEMBER,
network.MSG_MHF_INFO_GUILD,
network.MSG_MHF_ENUMERATE_GUILD,
network.MSG_MHF_UPDATE_GUILD,
network.MSG_MHF_ARRANGE_GUILD_MEMBER,
network.MSG_MHF_ENUMERATE_GUILD_MEMBER,
network.MSG_MHF_ENUMERATE_CAMPAIGN,
network.MSG_MHF_STATE_CAMPAIGN,
network.MSG_MHF_APPLY_CAMPAIGN,
network.MSG_MHF_ENUMERATE_ITEM,
network.MSG_MHF_ACQUIRE_ITEM,
network.MSG_MHF_TRANSFER_ITEM,
network.MSG_MHF_MERCENARY_HUNTDATA,
network.MSG_MHF_ENTRY_ROOKIE_GUILD,
network.MSG_MHF_ENUMERATE_QUEST,
network.MSG_MHF_ENUMERATE_EVENT,
network.MSG_MHF_ENUMERATE_PRICE,
network.MSG_MHF_ENUMERATE_RANKING,
network.MSG_MHF_ENUMERATE_ORDER,
network.MSG_MHF_ENUMERATE_SHOP,
network.MSG_MHF_GET_EXTRA_INFO,
network.MSG_MHF_UPDATE_INTERIOR,
network.MSG_MHF_ENUMERATE_HOUSE,
network.MSG_MHF_UPDATE_HOUSE,
network.MSG_MHF_LOAD_HOUSE,
network.MSG_MHF_OPERATE_WAREHOUSE,
network.MSG_MHF_ENUMERATE_WAREHOUSE,
network.MSG_MHF_UPDATE_WAREHOUSE,
network.MSG_MHF_ACQUIRE_TITLE,
network.MSG_MHF_ENUMERATE_TITLE,
network.MSG_MHF_ENUMERATE_GUILD_ITEM,
network.MSG_MHF_UPDATE_GUILD_ITEM,
network.MSG_MHF_ENUMERATE_UNION_ITEM,
network.MSG_MHF_UPDATE_UNION_ITEM,
network.MSG_MHF_CREATE_JOINT,
network.MSG_MHF_OPERATE_JOINT,
network.MSG_MHF_INFO_JOINT,
network.MSG_MHF_UPDATE_GUILD_ICON,
network.MSG_MHF_INFO_FESTA,
network.MSG_MHF_ENTRY_FESTA,
network.MSG_MHF_CHARGE_FESTA,
network.MSG_MHF_ACQUIRE_FESTA,
network.MSG_MHF_STATE_FESTA_U,
network.MSG_MHF_STATE_FESTA_G,
network.MSG_MHF_ENUMERATE_FESTA_MEMBER,
network.MSG_MHF_VOTE_FESTA,
network.MSG_MHF_ACQUIRE_CAFE_ITEM,
network.MSG_MHF_UPDATE_CAFEPOINT,
network.MSG_MHF_CHECK_DAILY_CAFEPOINT,
network.MSG_MHF_GET_COG_INFO,
network.MSG_MHF_CHECK_MONTHLY_ITEM,
network.MSG_MHF_ACQUIRE_MONTHLY_ITEM,
network.MSG_MHF_CHECK_WEEKLY_STAMP,
network.MSG_MHF_EXCHANGE_WEEKLY_STAMP,
network.MSG_MHF_CREATE_MERCENARY,
network.MSG_MHF_SAVE_MERCENARY,
network.MSG_MHF_READ_MERCENARY_W,
network.MSG_MHF_READ_MERCENARY_M,
network.MSG_MHF_CONTRACT_MERCENARY,
network.MSG_MHF_ENUMERATE_MERCENARY_LOG,
network.MSG_MHF_ENUMERATE_GUACOT,
network.MSG_MHF_UPDATE_GUACOT,
network.MSG_MHF_INFO_TOURNAMENT,
network.MSG_MHF_ENTRY_TOURNAMENT,
network.MSG_MHF_ENTER_TOURNAMENT_QUEST,
network.MSG_MHF_ACQUIRE_TOURNAMENT,
network.MSG_MHF_GET_ACHIEVEMENT,
network.MSG_MHF_RESET_ACHIEVEMENT,
network.MSG_MHF_ADD_ACHIEVEMENT,
network.MSG_MHF_PAYMENT_ACHIEVEMENT,
network.MSG_MHF_DISPLAYED_ACHIEVEMENT,
network.MSG_MHF_INFO_SCENARIO_COUNTER,
network.MSG_MHF_SAVE_SCENARIO_DATA,
network.MSG_MHF_LOAD_SCENARIO_DATA,
network.MSG_MHF_GET_BBS_SNS_STATUS,
network.MSG_MHF_APPLY_BBS_ARTICLE,
network.MSG_MHF_GET_ETC_POINTS,
network.MSG_MHF_UPDATE_ETC_POINT,
network.MSG_MHF_GET_MYHOUSE_INFO,
network.MSG_MHF_UPDATE_MYHOUSE_INFO,
network.MSG_MHF_GET_WEEKLY_SCHEDULE,
network.MSG_MHF_ENUMERATE_INV_GUILD,
network.MSG_MHF_OPERATION_INV_GUILD,
network.MSG_MHF_STAMPCARD_STAMP,
network.MSG_MHF_STAMPCARD_PRIZE,
network.MSG_MHF_UNRESERVE_SRG,
network.MSG_MHF_LOAD_PLATE_DATA,
network.MSG_MHF_SAVE_PLATE_DATA,
network.MSG_MHF_LOAD_PLATE_BOX,
network.MSG_MHF_SAVE_PLATE_BOX,
network.MSG_MHF_READ_GUILDCARD,
network.MSG_MHF_UPDATE_GUILDCARD,
network.MSG_MHF_READ_BEAT_LEVEL,
network.MSG_MHF_UPDATE_BEAT_LEVEL,
network.MSG_MHF_READ_BEAT_LEVEL_ALL_RANKING,
network.MSG_MHF_READ_BEAT_LEVEL_MY_RANKING,
network.MSG_MHF_READ_LAST_WEEK_BEAT_RANKING,
network.MSG_MHF_ACCEPT_READ_REWARD,
network.MSG_MHF_GET_ADDITIONAL_BEAT_REWARD,
network.MSG_MHF_GET_FIXED_SEIBATU_RANKING_TABLE,
network.MSG_MHF_GET_BBS_USER_STATUS,
network.MSG_MHF_KICK_EXPORT_FORCE,
network.MSG_MHF_GET_BREAK_SEIBATU_LEVEL_REWARD,
network.MSG_MHF_GET_WEEKLY_SEIBATU_RANKING_REWARD,
network.MSG_MHF_GET_EARTH_STATUS,
network.MSG_MHF_LOAD_PARTNER,
network.MSG_MHF_SAVE_PARTNER,
network.MSG_MHF_GET_GUILD_MISSION_LIST,
network.MSG_MHF_GET_GUILD_MISSION_RECORD,
network.MSG_MHF_ADD_GUILD_MISSION_COUNT,
network.MSG_MHF_SET_GUILD_MISSION_TARGET,
network.MSG_MHF_CANCEL_GUILD_MISSION_TARGET,
network.MSG_MHF_LOAD_OTOMO_AIROU,
network.MSG_MHF_SAVE_OTOMO_AIROU,
network.MSG_MHF_ENUMERATE_GUILD_TRESURE,
network.MSG_MHF_ENUMERATE_AIROULIST,
network.MSG_MHF_REGIST_GUILD_TRESURE,
network.MSG_MHF_ACQUIRE_GUILD_TRESURE,
network.MSG_MHF_OPERATE_GUILD_TRESURE_REPORT,
network.MSG_MHF_GET_GUILD_TRESURE_SOUVENIR,
network.MSG_MHF_ACQUIRE_GUILD_TRESURE_SOUVENIR,
network.MSG_MHF_ENUMERATE_FESTA_INTERMEDIATE_PRIZE,
network.MSG_MHF_ACQUIRE_FESTA_INTERMEDIATE_PRIZE,
network.MSG_MHF_LOAD_DECO_MYSET,
network.MSG_MHF_SAVE_DECO_MYSET,
network.MSG_MHF_reserve10F,
network.MSG_MHF_LOAD_GUILD_COOKING,
network.MSG_MHF_REGIST_GUILD_COOKING,
network.MSG_MHF_LOAD_GUILD_ADVENTURE,
network.MSG_MHF_REGIST_GUILD_ADVENTURE,
network.MSG_MHF_ACQUIRE_GUILD_ADVENTURE,
network.MSG_MHF_CHARGE_GUILD_ADVENTURE,
network.MSG_MHF_LOAD_LEGEND_DISPATCH,
network.MSG_MHF_LOAD_HUNTER_NAVI,
network.MSG_MHF_SAVE_HUNTER_NAVI,
network.MSG_MHF_REGIST_SPABI_TIME,
network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_MASTER,
network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_ACTIVE_COUNT,
network.MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER,
network.MSG_MHF_GET_TOWER_INFO,
network.MSG_MHF_POST_TOWER_INFO,
network.MSG_MHF_GET_GEM_INFO,
network.MSG_MHF_POST_GEM_INFO,
network.MSG_MHF_GET_EARTH_VALUE,
network.MSG_MHF_DEBUG_POST_VALUE,
network.MSG_MHF_GET_PAPER_DATA,
network.MSG_MHF_GET_NOTICE,
network.MSG_MHF_POST_NOTICE,
network.MSG_MHF_GET_BOOST_TIME,
network.MSG_MHF_POST_BOOST_TIME,
network.MSG_MHF_GET_BOOST_TIME_LIMIT,
network.MSG_MHF_POST_BOOST_TIME_LIMIT,
network.MSG_MHF_ENUMERATE_FESTA_PERSONAL_PRIZE,
network.MSG_MHF_ACQUIRE_FESTA_PERSONAL_PRIZE,
network.MSG_MHF_GET_RAND_FROM_TABLE,
network.MSG_MHF_GET_CAFE_DURATION,
network.MSG_MHF_GET_CAFE_DURATION_BONUS_INFO,
network.MSG_MHF_RECEIVE_CAFE_DURATION_BONUS,
network.MSG_MHF_POST_CAFE_DURATION_BONUS_RECEIVED,
network.MSG_MHF_GET_GACHA_POINT,
network.MSG_MHF_USE_GACHA_POINT,
network.MSG_MHF_EXCHANGE_FPOINT_2_ITEM,
network.MSG_MHF_EXCHANGE_ITEM_2_FPOINT,
network.MSG_MHF_GET_FPOINT_EXCHANGE_LIST,
network.MSG_MHF_PLAY_STEPUP_GACHA,
network.MSG_MHF_RECEIVE_GACHA_ITEM,
network.MSG_MHF_GET_STEPUP_STATUS,
network.MSG_MHF_PLAY_FREE_GACHA,
network.MSG_MHF_GET_TINY_BIN,
network.MSG_MHF_POST_TINY_BIN,
network.MSG_MHF_GET_SENYU_DAILY_COUNT,
network.MSG_MHF_GET_GUILD_TARGET_MEMBER_NUM,
network.MSG_MHF_GET_BOOST_RIGHT,
network.MSG_MHF_START_BOOST_TIME,
network.MSG_MHF_POST_BOOST_TIME_QUEST_RETURN,
network.MSG_MHF_GET_BOX_GACHA_INFO,
network.MSG_MHF_PLAY_BOX_GACHA,
network.MSG_MHF_RESET_BOX_GACHA_INFO,
network.MSG_MHF_GET_SEIBATTLE,
network.MSG_MHF_POST_SEIBATTLE,
network.MSG_MHF_GET_RYOUDAMA,
network.MSG_MHF_POST_RYOUDAMA,
network.MSG_MHF_GET_TENROUIRAI,
network.MSG_MHF_POST_TENROUIRAI,
network.MSG_MHF_POST_GUILD_SCOUT,
network.MSG_MHF_CANCEL_GUILD_SCOUT,
network.MSG_MHF_ANSWER_GUILD_SCOUT,
network.MSG_MHF_GET_GUILD_SCOUT_LIST,
network.MSG_MHF_GET_GUILD_MANAGE_RIGHT,
network.MSG_MHF_SET_GUILD_MANAGE_RIGHT,
network.MSG_MHF_PLAY_NORMAL_GACHA,
network.MSG_MHF_GET_DAILY_MISSION_MASTER,
network.MSG_MHF_GET_DAILY_MISSION_PERSONAL,
network.MSG_MHF_SET_DAILY_MISSION_PERSONAL,
network.MSG_MHF_GET_GACHA_PLAY_HISTORY,
network.MSG_MHF_GET_REJECT_GUILD_SCOUT,
network.MSG_MHF_SET_REJECT_GUILD_SCOUT,
network.MSG_MHF_GET_CA_ACHIEVEMENT_HIST,
network.MSG_MHF_SET_CA_ACHIEVEMENT_HIST,
network.MSG_MHF_GET_KEEP_LOGIN_BOOST_STATUS,
network.MSG_MHF_USE_KEEP_LOGIN_BOOST,
network.MSG_MHF_GET_UD_SCHEDULE,
network.MSG_MHF_GET_UD_INFO,
network.MSG_MHF_GET_KIJU_INFO,
network.MSG_MHF_SET_KIJU,
network.MSG_MHF_ADD_UD_POINT,
network.MSG_MHF_GET_UD_MY_POINT,
network.MSG_MHF_GET_UD_TOTAL_POINT_INFO,
network.MSG_MHF_GET_UD_BONUS_QUEST_INFO,
network.MSG_MHF_GET_UD_SELECTED_COLOR_INFO,
network.MSG_MHF_GET_UD_MONSTER_POINT,
network.MSG_MHF_GET_UD_DAILY_PRESENT_LIST,
network.MSG_MHF_GET_UD_NORMA_PRESENT_LIST,
network.MSG_MHF_GET_UD_RANKING_REWARD_LIST,
network.MSG_MHF_ACQUIRE_UD_ITEM,
network.MSG_MHF_GET_REWARD_SONG,
network.MSG_MHF_USE_REWARD_SONG,
network.MSG_MHF_ADD_REWARD_SONG_COUNT,
network.MSG_MHF_GET_UD_RANKING,
network.MSG_MHF_GET_UD_MY_RANKING,
network.MSG_MHF_ACQUIRE_MONTHLY_REWARD,
network.MSG_MHF_GET_UD_GUILD_MAP_INFO,
network.MSG_MHF_GENERATE_UD_GUILD_MAP,
network.MSG_MHF_GET_UD_TACTICS_POINT,
network.MSG_MHF_ADD_UD_TACTICS_POINT,
network.MSG_MHF_GET_UD_TACTICS_RANKING,
network.MSG_MHF_GET_UD_TACTICS_REWARD_LIST,
network.MSG_MHF_GET_UD_TACTICS_LOG,
network.MSG_MHF_GET_EQUIP_SKIN_HIST,
network.MSG_MHF_UPDATE_EQUIP_SKIN_HIST,
network.MSG_MHF_GET_UD_TACTICS_FOLLOWER,
network.MSG_MHF_SET_UD_TACTICS_FOLLOWER,
network.MSG_MHF_GET_UD_SHOP_COIN,
network.MSG_MHF_USE_UD_SHOP_COIN,
network.MSG_MHF_GET_ENHANCED_MINIDATA,
network.MSG_MHF_SET_ENHANCED_MINIDATA,
network.MSG_MHF_SEX_CHANGER,
network.MSG_MHF_GET_LOBBY_CROWD,
network.MSG_SYS_reserve180,
network.MSG_MHF_GUILD_HUNTDATA,
network.MSG_MHF_ADD_KOURYOU_POINT,
network.MSG_MHF_GET_KOURYOU_POINT,
network.MSG_MHF_EXCHANGE_KOURYOU_POINT,
network.MSG_MHF_GET_UD_TACTICS_BONUS_QUEST,
network.MSG_MHF_GET_UD_TACTICS_FIRST_QUEST_BONUS,
network.MSG_MHF_GET_UD_TACTICS_REMAINING_POINT,
network.MSG_SYS_reserve188,
network.MSG_MHF_LOAD_PLATE_MYSET,
network.MSG_MHF_SAVE_PLATE_MYSET,
network.MSG_SYS_reserve18B,
network.MSG_MHF_GET_RESTRICTION_EVENT,
network.MSG_MHF_SET_RESTRICTION_EVENT,
network.MSG_SYS_reserve18E,
network.MSG_SYS_reserve18F,
network.MSG_MHF_GET_TREND_WEAPON,
network.MSG_MHF_UPDATE_USE_TREND_WEAPON_LOG,
network.MSG_SYS_reserve192,
network.MSG_SYS_reserve193,
network.MSG_SYS_reserve194,
network.MSG_MHF_SAVE_RENGOKU_DATA,
network.MSG_MHF_LOAD_RENGOKU_DATA,
network.MSG_MHF_GET_RENGOKU_BINARY,
network.MSG_MHF_ENUMERATE_RENGOKU_RANKING,
network.MSG_MHF_GET_RENGOKU_RANKING_RANK,
network.MSG_MHF_ACQUIRE_EXCHANGE_SHOP,
network.MSG_SYS_reserve19B,
network.MSG_MHF_SAVE_MEZFES_DATA,
network.MSG_MHF_LOAD_MEZFES_DATA,
network.MSG_SYS_reserve19E,
network.MSG_SYS_reserve19F,
network.MSG_MHF_UPDATE_FORCE_GUILD_RANK,
network.MSG_MHF_RESET_TITLE,
network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD,
network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD,
network.MSG_SYS_reserve1A4,
network.MSG_MHF_REGIST_GUILD_ADVENTURE_DIVA,
network.MSG_SYS_reserve1A6,
network.MSG_SYS_reserve1A7,
network.MSG_SYS_reserve1A8,
network.MSG_SYS_reserve1A9,
network.MSG_SYS_reserve1AA,
network.MSG_SYS_reserve1AB,
network.MSG_SYS_reserve1AC,
network.MSG_SYS_reserve1AD,
network.MSG_SYS_reserve1AE,
network.MSG_SYS_reserve1AF,
}
for _, opcode := range opcodes {
t.Run(opcode.String(), func(t *testing.T) {
pkt := FromOpcode(opcode)
if pkt == nil {
t.Errorf("FromOpcode(%s) returned nil", opcode)
return
}
// Verify Opcode() returns the correct value
if pkt.Opcode() != opcode {
t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), opcode)
}
})
}
}
// TestAckHandlePacketsParse tests parsing of packets with simple AckHandle uint32 field
func TestAckHandlePacketsParse(t *testing.T) {
testCases := []struct {
name string
opcode network.PacketID
}{
{"MsgMhfGetAchievement", network.MSG_MHF_GET_ACHIEVEMENT},
{"MsgMhfGetTowerInfo", network.MSG_MHF_GET_TOWER_INFO},
{"MsgMhfGetGemInfo", network.MSG_MHF_GET_GEM_INFO},
{"MsgMhfGetBoostTime", network.MSG_MHF_GET_BOOST_TIME},
{"MsgMhfGetCafeDuration", network.MSG_MHF_GET_CAFE_DURATION},
{"MsgMhfGetGachaPoint", network.MSG_MHF_GET_GACHA_POINT},
{"MsgMhfLoadPartner", network.MSG_MHF_LOAD_PARTNER},
{"MsgMhfLoadOtomoAirou", network.MSG_MHF_LOAD_OTOMO_AIROU},
{"MsgMhfLoadPlateData", network.MSG_MHF_LOAD_PLATE_DATA},
{"MsgMhfLoadPlateBox", network.MSG_MHF_LOAD_PLATE_BOX},
{"MsgMhfLoadDecoMyset", network.MSG_MHF_LOAD_DECO_MYSET},
{"MsgMhfLoadGuildCooking", network.MSG_MHF_LOAD_GUILD_COOKING},
{"MsgMhfLoadGuildAdventure", network.MSG_MHF_LOAD_GUILD_ADVENTURE},
{"MsgMhfLoadHunterNavi", network.MSG_MHF_LOAD_HUNTER_NAVI},
{"MsgMhfInfoFesta", network.MSG_MHF_INFO_FESTA},
{"MsgMhfInfoTournament", network.MSG_MHF_INFO_TOURNAMENT},
{"MsgMhfEnumerateQuest", network.MSG_MHF_ENUMERATE_QUEST},
{"MsgMhfEnumerateEvent", network.MSG_MHF_ENUMERATE_EVENT},
{"MsgMhfEnumerateShop", network.MSG_MHF_ENUMERATE_SHOP},
{"MsgMhfEnumerateRanking", network.MSG_MHF_ENUMERATE_RANKING},
{"MsgMhfEnumerateOrder", network.MSG_MHF_ENUMERATE_ORDER},
{"MsgMhfEnumerateCampaign", network.MSG_MHF_ENUMERATE_CAMPAIGN},
{"MsgMhfGetWeeklySchedule", network.MSG_MHF_GET_WEEKLY_SCHEDULE},
{"MsgMhfGetUdSchedule", network.MSG_MHF_GET_UD_SCHEDULE},
{"MsgMhfGetUdInfo", network.MSG_MHF_GET_UD_INFO},
{"MsgMhfGetKijuInfo", network.MSG_MHF_GET_KIJU_INFO},
{"MsgMhfGetExtraInfo", network.MSG_MHF_GET_EXTRA_INFO},
{"MsgMhfGetCogInfo", network.MSG_MHF_GET_COG_INFO},
}
ctx := &clientctx.ClientContext{RealClientMode: cfg.ZZ}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
pkt := FromOpcode(tc.opcode)
if pkt == nil {
t.Skipf("FromOpcode(%s) returned nil", tc.opcode)
return
}
// Create test data - most of these packets read AckHandle + additional data
bf := byteframe.NewByteFrame()
bf.WriteUint32(0x12345678) // AckHandle
// Write extra padding bytes for packets that expect more data
for i := 0; i < 32; i++ {
bf.WriteUint32(uint32(i))
}
_, _ = bf.Seek(0, io.SeekStart)
// Parse should not panic
err := pkt.Parse(bf, ctx)
if err != nil {
t.Logf("Parse() returned error (may be expected): %v", err)
}
})
}
}
// TestAddAchievementParse tests MsgMhfAddAchievement Parse
func TestAddAchievementParse(t *testing.T) {
tests := []struct {
name string
achievementID uint8
unk1 uint16
unk2 uint16
}{
{"typical values", 1, 100, 200},
{"zero values", 0, 0, 0},
{"max values", 255, 65535, 65535},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bf := byteframe.NewByteFrame()
bf.WriteUint8(tt.achievementID)
bf.WriteUint16(tt.unk1)
bf.WriteUint16(tt.unk2)
_, _ = bf.Seek(0, io.SeekStart)
pkt := &MsgMhfAddAchievement{}
err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ})
if err != nil {
t.Fatalf("Parse() error = %v", err)
}
if pkt.AchievementID != tt.achievementID {
t.Errorf("AchievementID = %d, want %d", pkt.AchievementID, tt.achievementID)
}
if pkt.Unk1 != tt.unk1 {
t.Errorf("Unk1 = %d, want %d", pkt.Unk1, tt.unk1)
}
if pkt.Unk2 != tt.unk2 {
t.Errorf("Unk2 = %d, want %d", pkt.Unk2, tt.unk2)
}
})
}
}
// TestGetAchievementParse tests MsgMhfGetAchievement Parse
func TestGetAchievementParse(t *testing.T) {
tests := []struct {
name string
ackHandle uint32
charID uint32
unk1 uint32
}{
{"typical values", 1, 12345, 0},
{"large values", 0xFFFFFFFF, 0xDEADBEEF, 0xCAFEBABE},
{"zero values", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bf := byteframe.NewByteFrame()
bf.WriteUint32(tt.ackHandle)
bf.WriteUint32(tt.charID)
bf.WriteUint32(tt.unk1)
_, _ = bf.Seek(0, io.SeekStart)
pkt := &MsgMhfGetAchievement{}
err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ})
if err != nil {
t.Fatalf("Parse() error = %v", err)
}
if pkt.AckHandle != tt.ackHandle {
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle)
}
if pkt.CharID != tt.charID {
t.Errorf("CharID = %d, want %d", pkt.CharID, tt.charID)
}
// Unk1 (third uint32) is read and discarded in Parse on main
})
}
}
// TestBuildNotImplemented tests that Build returns error for packets without implementation
func TestBuildNotImplemented(t *testing.T) {
packetsToTest := []MHFPacket{
&MsgMhfAddAchievement{},
&MsgMhfGetAchievement{},
&MsgMhfAcquireItem{},
&MsgMhfEnumerateGuild{},
&MsgMhfInfoGuild{},
&MsgMhfCreateGuild{},
&MsgMhfOperateGuild{},
&MsgMhfOperateGuildMember{},
&MsgMhfUpdateGuild{},
&MsgMhfArrangeGuildMember{},
&MsgMhfEnumerateGuildMember{},
&MsgMhfInfoFesta{},
&MsgMhfEntryFesta{},
&MsgMhfChargeFesta{},
&MsgMhfAcquireFesta{},
&MsgMhfVoteFesta{},
&MsgMhfInfoTournament{},
&MsgMhfEntryTournament{},
&MsgMhfAcquireTournament{},
}
for _, pkt := range packetsToTest {
t.Run(pkt.Opcode().String(), func(t *testing.T) {
bf := byteframe.NewByteFrame()
err := pkt.Build(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ})
if err == nil {
t.Logf("Build() did not return error (implementation may exist)")
} else {
// Expected - Build is not implemented
if err.Error() != "NOT IMPLEMENTED" {
t.Logf("Build() returned unexpected error: %v", err)
}
}
})
}
}
// TestReservePacketsOpcode tests that reserve packets have correct opcodes
func TestReservePacketsOpcode(t *testing.T) {
reservePackets := []struct {
opcode network.PacketID
}{
{network.MSG_SYS_reserve01},
{network.MSG_SYS_reserve02},
{network.MSG_SYS_reserve03},
{network.MSG_SYS_reserve04},
{network.MSG_SYS_reserve05},
{network.MSG_SYS_reserve06},
{network.MSG_SYS_reserve07},
{network.MSG_SYS_reserve0C},
{network.MSG_SYS_reserve0D},
{network.MSG_SYS_reserve0E},
{network.MSG_SYS_reserve4A},
{network.MSG_SYS_reserve4B},
{network.MSG_SYS_reserve4C},
{network.MSG_SYS_reserve4D},
{network.MSG_SYS_reserve4E},
{network.MSG_SYS_reserve4F},
{network.MSG_SYS_reserve55},
{network.MSG_SYS_reserve56},
{network.MSG_SYS_reserve57},
{network.MSG_SYS_reserve5C},
{network.MSG_SYS_reserve5E},
{network.MSG_SYS_reserve5F},
{network.MSG_SYS_reserve71},
{network.MSG_SYS_reserve72},
{network.MSG_SYS_reserve73},
{network.MSG_SYS_reserve74},
{network.MSG_SYS_reserve75},
{network.MSG_SYS_reserve76},
{network.MSG_SYS_reserve77},
{network.MSG_SYS_reserve78},
{network.MSG_SYS_reserve79},
{network.MSG_SYS_reserve7A},
{network.MSG_SYS_reserve7B},
{network.MSG_SYS_reserve7C},
{network.MSG_SYS_reserve7E},
{network.MSG_SYS_reserve180},
{network.MSG_SYS_reserve188},
{network.MSG_SYS_reserve18B},
{network.MSG_SYS_reserve18E},
{network.MSG_SYS_reserve18F},
{network.MSG_SYS_reserve192},
{network.MSG_SYS_reserve193},
{network.MSG_SYS_reserve194},
{network.MSG_SYS_reserve19B},
{network.MSG_SYS_reserve19E},
{network.MSG_SYS_reserve19F},
{network.MSG_SYS_reserve1A4},
{network.MSG_SYS_reserve1A6},
{network.MSG_SYS_reserve1A7},
{network.MSG_SYS_reserve1A8},
{network.MSG_SYS_reserve1A9},
{network.MSG_SYS_reserve1AA},
{network.MSG_SYS_reserve1AB},
{network.MSG_SYS_reserve1AC},
{network.MSG_SYS_reserve1AD},
{network.MSG_SYS_reserve1AE},
{network.MSG_SYS_reserve1AF},
}
for _, tc := range reservePackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
pkt := FromOpcode(tc.opcode)
if pkt == nil {
t.Errorf("FromOpcode(%s) returned nil", tc.opcode)
return
}
if pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), tc.opcode)
}
})
}
}
// TestMHFPacketsOpcode tests Opcode() method for various MHF packets
func TestMHFPacketsOpcode(t *testing.T) {
mhfPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfSavedata{}, network.MSG_MHF_SAVEDATA},
{&MsgMhfLoaddata{}, network.MSG_MHF_LOADDATA},
{&MsgMhfListMember{}, network.MSG_MHF_LIST_MEMBER},
{&MsgMhfOprMember{}, network.MSG_MHF_OPR_MEMBER},
{&MsgMhfEnumerateDistItem{}, network.MSG_MHF_ENUMERATE_DIST_ITEM},
{&MsgMhfApplyDistItem{}, network.MSG_MHF_APPLY_DIST_ITEM},
{&MsgMhfAcquireDistItem{}, network.MSG_MHF_ACQUIRE_DIST_ITEM},
{&MsgMhfGetDistDescription{}, network.MSG_MHF_GET_DIST_DESCRIPTION},
{&MsgMhfSendMail{}, network.MSG_MHF_SEND_MAIL},
{&MsgMhfReadMail{}, network.MSG_MHF_READ_MAIL},
{&MsgMhfListMail{}, network.MSG_MHF_LIST_MAIL},
{&MsgMhfOprtMail{}, network.MSG_MHF_OPRT_MAIL},
{&MsgMhfLoadFavoriteQuest{}, network.MSG_MHF_LOAD_FAVORITE_QUEST},
{&MsgMhfSaveFavoriteQuest{}, network.MSG_MHF_SAVE_FAVORITE_QUEST},
{&MsgMhfRegisterEvent{}, network.MSG_MHF_REGISTER_EVENT},
{&MsgMhfReleaseEvent{}, network.MSG_MHF_RELEASE_EVENT},
{&MsgMhfTransitMessage{}, network.MSG_MHF_TRANSIT_MESSAGE},
{&MsgMhfPresentBox{}, network.MSG_MHF_PRESENT_BOX},
{&MsgMhfServerCommand{}, network.MSG_MHF_SERVER_COMMAND},
{&MsgMhfShutClient{}, network.MSG_MHF_SHUT_CLIENT},
{&MsgMhfAnnounce{}, network.MSG_MHF_ANNOUNCE},
{&MsgMhfSetLoginwindow{}, network.MSG_MHF_SET_LOGINWINDOW},
{&MsgMhfGetCaUniqueID{}, network.MSG_MHF_GET_CA_UNIQUE_ID},
{&MsgMhfSetCaAchievement{}, network.MSG_MHF_SET_CA_ACHIEVEMENT},
{&MsgMhfCaravanMyScore{}, network.MSG_MHF_CARAVAN_MY_SCORE},
{&MsgMhfCaravanRanking{}, network.MSG_MHF_CARAVAN_RANKING},
{&MsgMhfCaravanMyRank{}, network.MSG_MHF_CARAVAN_MY_RANK},
}
for _, tc := range mhfPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestGuildPacketsOpcode tests guild-related packets
func TestGuildPacketsOpcode(t *testing.T) {
guildPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfCreateGuild{}, network.MSG_MHF_CREATE_GUILD},
{&MsgMhfOperateGuild{}, network.MSG_MHF_OPERATE_GUILD},
{&MsgMhfOperateGuildMember{}, network.MSG_MHF_OPERATE_GUILD_MEMBER},
{&MsgMhfInfoGuild{}, network.MSG_MHF_INFO_GUILD},
{&MsgMhfEnumerateGuild{}, network.MSG_MHF_ENUMERATE_GUILD},
{&MsgMhfUpdateGuild{}, network.MSG_MHF_UPDATE_GUILD},
{&MsgMhfArrangeGuildMember{}, network.MSG_MHF_ARRANGE_GUILD_MEMBER},
{&MsgMhfEnumerateGuildMember{}, network.MSG_MHF_ENUMERATE_GUILD_MEMBER},
{&MsgMhfEnumerateGuildItem{}, network.MSG_MHF_ENUMERATE_GUILD_ITEM},
{&MsgMhfUpdateGuildItem{}, network.MSG_MHF_UPDATE_GUILD_ITEM},
{&MsgMhfUpdateGuildIcon{}, network.MSG_MHF_UPDATE_GUILD_ICON},
{&MsgMhfEnumerateGuildTresure{}, network.MSG_MHF_ENUMERATE_GUILD_TRESURE},
{&MsgMhfRegistGuildTresure{}, network.MSG_MHF_REGIST_GUILD_TRESURE},
{&MsgMhfAcquireGuildTresure{}, network.MSG_MHF_ACQUIRE_GUILD_TRESURE},
{&MsgMhfOperateGuildTresureReport{}, network.MSG_MHF_OPERATE_GUILD_TRESURE_REPORT},
{&MsgMhfGetGuildTresureSouvenir{}, network.MSG_MHF_GET_GUILD_TRESURE_SOUVENIR},
{&MsgMhfAcquireGuildTresureSouvenir{}, network.MSG_MHF_ACQUIRE_GUILD_TRESURE_SOUVENIR},
{&MsgMhfLoadGuildCooking{}, network.MSG_MHF_LOAD_GUILD_COOKING},
{&MsgMhfRegistGuildCooking{}, network.MSG_MHF_REGIST_GUILD_COOKING},
{&MsgMhfLoadGuildAdventure{}, network.MSG_MHF_LOAD_GUILD_ADVENTURE},
{&MsgMhfRegistGuildAdventure{}, network.MSG_MHF_REGIST_GUILD_ADVENTURE},
{&MsgMhfAcquireGuildAdventure{}, network.MSG_MHF_ACQUIRE_GUILD_ADVENTURE},
{&MsgMhfChargeGuildAdventure{}, network.MSG_MHF_CHARGE_GUILD_ADVENTURE},
{&MsgMhfGetGuildMissionList{}, network.MSG_MHF_GET_GUILD_MISSION_LIST},
{&MsgMhfGetGuildMissionRecord{}, network.MSG_MHF_GET_GUILD_MISSION_RECORD},
{&MsgMhfAddGuildMissionCount{}, network.MSG_MHF_ADD_GUILD_MISSION_COUNT},
{&MsgMhfSetGuildMissionTarget{}, network.MSG_MHF_SET_GUILD_MISSION_TARGET},
{&MsgMhfCancelGuildMissionTarget{}, network.MSG_MHF_CANCEL_GUILD_MISSION_TARGET},
{&MsgMhfGetGuildWeeklyBonusMaster{}, network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_MASTER},
{&MsgMhfGetGuildWeeklyBonusActiveCount{}, network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_ACTIVE_COUNT},
{&MsgMhfAddGuildWeeklyBonusExceptionalUser{}, network.MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER},
{&MsgMhfGetGuildTargetMemberNum{}, network.MSG_MHF_GET_GUILD_TARGET_MEMBER_NUM},
{&MsgMhfPostGuildScout{}, network.MSG_MHF_POST_GUILD_SCOUT},
{&MsgMhfCancelGuildScout{}, network.MSG_MHF_CANCEL_GUILD_SCOUT},
{&MsgMhfAnswerGuildScout{}, network.MSG_MHF_ANSWER_GUILD_SCOUT},
{&MsgMhfGetGuildScoutList{}, network.MSG_MHF_GET_GUILD_SCOUT_LIST},
{&MsgMhfGetGuildManageRight{}, network.MSG_MHF_GET_GUILD_MANAGE_RIGHT},
{&MsgMhfSetGuildManageRight{}, network.MSG_MHF_SET_GUILD_MANAGE_RIGHT},
{&MsgMhfGetRejectGuildScout{}, network.MSG_MHF_GET_REJECT_GUILD_SCOUT},
{&MsgMhfSetRejectGuildScout{}, network.MSG_MHF_SET_REJECT_GUILD_SCOUT},
{&MsgMhfGuildHuntdata{}, network.MSG_MHF_GUILD_HUNTDATA},
{&MsgMhfUpdateForceGuildRank{}, network.MSG_MHF_UPDATE_FORCE_GUILD_RANK},
{&MsgMhfEnumerateGuildMessageBoard{}, network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD},
{&MsgMhfUpdateGuildMessageBoard{}, network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD},
}
for _, tc := range guildPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestFestaPacketsOpcode tests festa-related packets
func TestFestaPacketsOpcode(t *testing.T) {
festaPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfInfoFesta{}, network.MSG_MHF_INFO_FESTA},
{&MsgMhfEntryFesta{}, network.MSG_MHF_ENTRY_FESTA},
{&MsgMhfChargeFesta{}, network.MSG_MHF_CHARGE_FESTA},
{&MsgMhfAcquireFesta{}, network.MSG_MHF_ACQUIRE_FESTA},
{&MsgMhfStateFestaU{}, network.MSG_MHF_STATE_FESTA_U},
{&MsgMhfStateFestaG{}, network.MSG_MHF_STATE_FESTA_G},
{&MsgMhfEnumerateFestaMember{}, network.MSG_MHF_ENUMERATE_FESTA_MEMBER},
{&MsgMhfVoteFesta{}, network.MSG_MHF_VOTE_FESTA},
{&MsgMhfEnumerateFestaIntermediatePrize{}, network.MSG_MHF_ENUMERATE_FESTA_INTERMEDIATE_PRIZE},
{&MsgMhfAcquireFestaIntermediatePrize{}, network.MSG_MHF_ACQUIRE_FESTA_INTERMEDIATE_PRIZE},
{&MsgMhfEnumerateFestaPersonalPrize{}, network.MSG_MHF_ENUMERATE_FESTA_PERSONAL_PRIZE},
{&MsgMhfAcquireFestaPersonalPrize{}, network.MSG_MHF_ACQUIRE_FESTA_PERSONAL_PRIZE},
}
for _, tc := range festaPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestCafePacketsOpcode tests cafe-related packets
func TestCafePacketsOpcode(t *testing.T) {
cafePackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfAcquireCafeItem{}, network.MSG_MHF_ACQUIRE_CAFE_ITEM},
{&MsgMhfUpdateCafepoint{}, network.MSG_MHF_UPDATE_CAFEPOINT},
{&MsgMhfCheckDailyCafepoint{}, network.MSG_MHF_CHECK_DAILY_CAFEPOINT},
{&MsgMhfGetCafeDuration{}, network.MSG_MHF_GET_CAFE_DURATION},
{&MsgMhfGetCafeDurationBonusInfo{}, network.MSG_MHF_GET_CAFE_DURATION_BONUS_INFO},
{&MsgMhfReceiveCafeDurationBonus{}, network.MSG_MHF_RECEIVE_CAFE_DURATION_BONUS},
{&MsgMhfPostCafeDurationBonusReceived{}, network.MSG_MHF_POST_CAFE_DURATION_BONUS_RECEIVED},
}
for _, tc := range cafePackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestGachaPacketsOpcode tests gacha-related packets
func TestGachaPacketsOpcode(t *testing.T) {
gachaPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfGetGachaPoint{}, network.MSG_MHF_GET_GACHA_POINT},
{&MsgMhfUseGachaPoint{}, network.MSG_MHF_USE_GACHA_POINT},
{&MsgMhfPlayStepupGacha{}, network.MSG_MHF_PLAY_STEPUP_GACHA},
{&MsgMhfReceiveGachaItem{}, network.MSG_MHF_RECEIVE_GACHA_ITEM},
{&MsgMhfGetStepupStatus{}, network.MSG_MHF_GET_STEPUP_STATUS},
{&MsgMhfPlayFreeGacha{}, network.MSG_MHF_PLAY_FREE_GACHA},
{&MsgMhfGetBoxGachaInfo{}, network.MSG_MHF_GET_BOX_GACHA_INFO},
{&MsgMhfPlayBoxGacha{}, network.MSG_MHF_PLAY_BOX_GACHA},
{&MsgMhfResetBoxGachaInfo{}, network.MSG_MHF_RESET_BOX_GACHA_INFO},
{&MsgMhfPlayNormalGacha{}, network.MSG_MHF_PLAY_NORMAL_GACHA},
{&MsgMhfGetGachaPlayHistory{}, network.MSG_MHF_GET_GACHA_PLAY_HISTORY},
}
for _, tc := range gachaPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestUDPacketsOpcode tests UD (Ultimate Devastation) related packets
func TestUDPacketsOpcode(t *testing.T) {
udPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfGetUdSchedule{}, network.MSG_MHF_GET_UD_SCHEDULE},
{&MsgMhfGetUdInfo{}, network.MSG_MHF_GET_UD_INFO},
{&MsgMhfAddUdPoint{}, network.MSG_MHF_ADD_UD_POINT},
{&MsgMhfGetUdMyPoint{}, network.MSG_MHF_GET_UD_MY_POINT},
{&MsgMhfGetUdTotalPointInfo{}, network.MSG_MHF_GET_UD_TOTAL_POINT_INFO},
{&MsgMhfGetUdBonusQuestInfo{}, network.MSG_MHF_GET_UD_BONUS_QUEST_INFO},
{&MsgMhfGetUdSelectedColorInfo{}, network.MSG_MHF_GET_UD_SELECTED_COLOR_INFO},
{&MsgMhfGetUdMonsterPoint{}, network.MSG_MHF_GET_UD_MONSTER_POINT},
{&MsgMhfGetUdDailyPresentList{}, network.MSG_MHF_GET_UD_DAILY_PRESENT_LIST},
{&MsgMhfGetUdNormaPresentList{}, network.MSG_MHF_GET_UD_NORMA_PRESENT_LIST},
{&MsgMhfGetUdRankingRewardList{}, network.MSG_MHF_GET_UD_RANKING_REWARD_LIST},
{&MsgMhfAcquireUdItem{}, network.MSG_MHF_ACQUIRE_UD_ITEM},
{&MsgMhfGetUdRanking{}, network.MSG_MHF_GET_UD_RANKING},
{&MsgMhfGetUdMyRanking{}, network.MSG_MHF_GET_UD_MY_RANKING},
{&MsgMhfGetUdGuildMapInfo{}, network.MSG_MHF_GET_UD_GUILD_MAP_INFO},
{&MsgMhfGenerateUdGuildMap{}, network.MSG_MHF_GENERATE_UD_GUILD_MAP},
{&MsgMhfGetUdTacticsPoint{}, network.MSG_MHF_GET_UD_TACTICS_POINT},
{&MsgMhfAddUdTacticsPoint{}, network.MSG_MHF_ADD_UD_TACTICS_POINT},
{&MsgMhfGetUdTacticsRanking{}, network.MSG_MHF_GET_UD_TACTICS_RANKING},
{&MsgMhfGetUdTacticsRewardList{}, network.MSG_MHF_GET_UD_TACTICS_REWARD_LIST},
{&MsgMhfGetUdTacticsLog{}, network.MSG_MHF_GET_UD_TACTICS_LOG},
{&MsgMhfGetUdTacticsFollower{}, network.MSG_MHF_GET_UD_TACTICS_FOLLOWER},
{&MsgMhfSetUdTacticsFollower{}, network.MSG_MHF_SET_UD_TACTICS_FOLLOWER},
{&MsgMhfGetUdShopCoin{}, network.MSG_MHF_GET_UD_SHOP_COIN},
{&MsgMhfUseUdShopCoin{}, network.MSG_MHF_USE_UD_SHOP_COIN},
{&MsgMhfGetUdTacticsBonusQuest{}, network.MSG_MHF_GET_UD_TACTICS_BONUS_QUEST},
{&MsgMhfGetUdTacticsFirstQuestBonus{}, network.MSG_MHF_GET_UD_TACTICS_FIRST_QUEST_BONUS},
{&MsgMhfGetUdTacticsRemainingPoint{}, network.MSG_MHF_GET_UD_TACTICS_REMAINING_POINT},
}
for _, tc := range udPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestRengokuPacketsOpcode tests rengoku (purgatory tower) related packets
func TestRengokuPacketsOpcode(t *testing.T) {
rengokuPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfSaveRengokuData{}, network.MSG_MHF_SAVE_RENGOKU_DATA},
{&MsgMhfLoadRengokuData{}, network.MSG_MHF_LOAD_RENGOKU_DATA},
{&MsgMhfGetRengokuBinary{}, network.MSG_MHF_GET_RENGOKU_BINARY},
{&MsgMhfEnumerateRengokuRanking{}, network.MSG_MHF_ENUMERATE_RENGOKU_RANKING},
{&MsgMhfGetRengokuRankingRank{}, network.MSG_MHF_GET_RENGOKU_RANKING_RANK},
}
for _, tc := range rengokuPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestMezFesPacketsOpcode tests Mezeporta Festival related packets
func TestMezFesPacketsOpcode(t *testing.T) {
mezfesPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfSaveMezfesData{}, network.MSG_MHF_SAVE_MEZFES_DATA},
{&MsgMhfLoadMezfesData{}, network.MSG_MHF_LOAD_MEZFES_DATA},
}
for _, tc := range mezfesPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestWarehousePacketsOpcode tests warehouse related packets
func TestWarehousePacketsOpcode(t *testing.T) {
warehousePackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfOperateWarehouse{}, network.MSG_MHF_OPERATE_WAREHOUSE},
{&MsgMhfEnumerateWarehouse{}, network.MSG_MHF_ENUMERATE_WAREHOUSE},
{&MsgMhfUpdateWarehouse{}, network.MSG_MHF_UPDATE_WAREHOUSE},
}
for _, tc := range warehousePackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestMercenaryPacketsOpcode tests mercenary related packets
func TestMercenaryPacketsOpcode(t *testing.T) {
mercenaryPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfMercenaryHuntdata{}, network.MSG_MHF_MERCENARY_HUNTDATA},
{&MsgMhfCreateMercenary{}, network.MSG_MHF_CREATE_MERCENARY},
{&MsgMhfSaveMercenary{}, network.MSG_MHF_SAVE_MERCENARY},
{&MsgMhfReadMercenaryW{}, network.MSG_MHF_READ_MERCENARY_W},
{&MsgMhfReadMercenaryM{}, network.MSG_MHF_READ_MERCENARY_M},
{&MsgMhfContractMercenary{}, network.MSG_MHF_CONTRACT_MERCENARY},
{&MsgMhfEnumerateMercenaryLog{}, network.MSG_MHF_ENUMERATE_MERCENARY_LOG},
}
for _, tc := range mercenaryPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestHousePacketsOpcode tests house related packets
func TestHousePacketsOpcode(t *testing.T) {
housePackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfUpdateInterior{}, network.MSG_MHF_UPDATE_INTERIOR},
{&MsgMhfEnumerateHouse{}, network.MSG_MHF_ENUMERATE_HOUSE},
{&MsgMhfUpdateHouse{}, network.MSG_MHF_UPDATE_HOUSE},
{&MsgMhfLoadHouse{}, network.MSG_MHF_LOAD_HOUSE},
{&MsgMhfGetMyhouseInfo{}, network.MSG_MHF_GET_MYHOUSE_INFO},
{&MsgMhfUpdateMyhouseInfo{}, network.MSG_MHF_UPDATE_MYHOUSE_INFO},
}
for _, tc := range housePackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestBoostPacketsOpcode tests boost related packets
func TestBoostPacketsOpcode(t *testing.T) {
boostPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfGetBoostTime{}, network.MSG_MHF_GET_BOOST_TIME},
{&MsgMhfPostBoostTime{}, network.MSG_MHF_POST_BOOST_TIME},
{&MsgMhfGetBoostTimeLimit{}, network.MSG_MHF_GET_BOOST_TIME_LIMIT},
{&MsgMhfPostBoostTimeLimit{}, network.MSG_MHF_POST_BOOST_TIME_LIMIT},
{&MsgMhfGetBoostRight{}, network.MSG_MHF_GET_BOOST_RIGHT},
{&MsgMhfStartBoostTime{}, network.MSG_MHF_START_BOOST_TIME},
{&MsgMhfPostBoostTimeQuestReturn{}, network.MSG_MHF_POST_BOOST_TIME_QUEST_RETURN},
{&MsgMhfGetKeepLoginBoostStatus{}, network.MSG_MHF_GET_KEEP_LOGIN_BOOST_STATUS},
{&MsgMhfUseKeepLoginBoost{}, network.MSG_MHF_USE_KEEP_LOGIN_BOOST},
}
for _, tc := range boostPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestTournamentPacketsOpcode tests tournament related packets
func TestTournamentPacketsOpcode(t *testing.T) {
tournamentPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfInfoTournament{}, network.MSG_MHF_INFO_TOURNAMENT},
{&MsgMhfEntryTournament{}, network.MSG_MHF_ENTRY_TOURNAMENT},
{&MsgMhfEnterTournamentQuest{}, network.MSG_MHF_ENTER_TOURNAMENT_QUEST},
{&MsgMhfAcquireTournament{}, network.MSG_MHF_ACQUIRE_TOURNAMENT},
}
for _, tc := range tournamentPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestPlatePacketsOpcode tests plate related packets
func TestPlatePacketsOpcode(t *testing.T) {
platePackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfLoadPlateData{}, network.MSG_MHF_LOAD_PLATE_DATA},
{&MsgMhfSavePlateData{}, network.MSG_MHF_SAVE_PLATE_DATA},
{&MsgMhfLoadPlateBox{}, network.MSG_MHF_LOAD_PLATE_BOX},
{&MsgMhfSavePlateBox{}, network.MSG_MHF_SAVE_PLATE_BOX},
{&MsgMhfLoadPlateMyset{}, network.MSG_MHF_LOAD_PLATE_MYSET},
{&MsgMhfSavePlateMyset{}, network.MSG_MHF_SAVE_PLATE_MYSET},
}
for _, tc := range platePackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}
// TestScenarioPacketsOpcode tests scenario related packets
func TestScenarioPacketsOpcode(t *testing.T) {
scenarioPackets := []struct {
pkt MHFPacket
opcode network.PacketID
}{
{&MsgMhfInfoScenarioCounter{}, network.MSG_MHF_INFO_SCENARIO_COUNTER},
{&MsgMhfSaveScenarioData{}, network.MSG_MHF_SAVE_SCENARIO_DATA},
{&MsgMhfLoadScenarioData{}, network.MSG_MHF_LOAD_SCENARIO_DATA},
}
for _, tc := range scenarioPackets {
t.Run(tc.opcode.String(), func(t *testing.T) {
if tc.pkt.Opcode() != tc.opcode {
t.Errorf("Opcode() = %s, want %s", tc.pkt.Opcode(), tc.opcode)
}
})
}
}