diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2014-05-27 13:33:54 -0700 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2014-05-27 13:33:54 -0700 |
commit | af4acff261d579428e8eef042cc5359fa392f725 (patch) | |
tree | ca73d54da799c3751e87ec88a785d60e7561a2f0 /src/char | |
parent | cac49afdef0992b93d8718fd928d73d721d434f4 (diff) | |
download | tmwa-af4acff261d579428e8eef042cc5359fa392f725.tar.gz tmwa-af4acff261d579428e8eef042cc5359fa392f725.tar.bz2 tmwa-af4acff261d579428e8eef042cc5359fa392f725.tar.xz tmwa-af4acff261d579428e8eef042cc5359fa392f725.zip |
Generate the char server protocol
Diffstat (limited to 'src/char')
-rw-r--r-- | src/char/char.cpp | 1457 | ||||
-rw-r--r-- | src/char/char.hpp | 4 | ||||
-rw-r--r-- | src/char/int_party.cpp | 420 | ||||
-rw-r--r-- | src/char/int_party.hpp | 2 | ||||
-rw-r--r-- | src/char/int_storage.cpp | 88 | ||||
-rw-r--r-- | src/char/int_storage.hpp | 4 | ||||
-rw-r--r-- | src/char/inter.cpp | 311 | ||||
-rw-r--r-- | src/char/inter.hpp | 4 |
8 files changed, 1280 insertions, 1010 deletions
diff --git a/src/char/char.cpp b/src/char/char.cpp index 790eeda..d36eb80 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -54,9 +54,15 @@ #include "../io/tty.hpp" #include "../io/write.hpp" +#include "../net/packets.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" -#include "../net/vomit.hpp" + +#include "../proto2/any-user.hpp" +#include "../proto2/login-admin.hpp" +#include "../proto2/login-char.hpp" +#include "../proto2/char-map.hpp" +#include "../proto2/char-user.hpp" #include "../mmo/config_parse.hpp" #include "../mmo/core.hpp" @@ -194,6 +200,14 @@ TimeT update_online; // to update online files when we receiving infor static pid_t pid = 0; // For forked DB writes + +auto iter_map_sessions() -> decltype(filter_iterator<Session *>(std::declval<Array<Session *, MAX_MAP_SERVERS> *>())) +{ + return filter_iterator<Session *>(&server_session); +} + + + static void create_online_files(void); @@ -621,7 +635,7 @@ void mmo_char_sync_timer(TimerData *, tick_t) // Function to create a new character //----------------------------------- static -CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], uint8_t slot, uint16_t hair_color, uint16_t hair_style) +CharPair *make_new_char(Session *s, CharName name, const Stats6& stats, uint8_t slot, uint16_t hair_color, uint16_t hair_style) { // ugh char_session_data *sd = static_cast<char_session_data *>(s->session_data.get()); @@ -674,16 +688,17 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui } } // else, all letters/symbols are authorised (except control char removed before) + // TODO this comment is obsolete // this is why it needs to be unsigned - if (stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5] != 5 * 6 || // stats + if (stats.str + stats.agi + stats.vit + stats.int_ + stats.dex + stats.luk != 5 * 6 || // stats slot >= 9 || hair_style >= 20 || hair_color >= 12) { CHAR_LOG("Make new char error (invalid values): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n"_fmt, s, sd->account_id, slot, name, - stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], - stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5], + stats.str, stats.agi, stats.vit, stats.int_, stats.dex, stats.luk, + stats.str + stats.agi + stats.vit + stats.int_ + stats.dex + stats.luk, hair_style, hair_color); return nullptr; } @@ -691,12 +706,13 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui // check individual stat value for (int i = 0; i < 6; i++) { - if (stats[i] < 1 || stats[i] > 9) + uint8_t statsi = reinterpret_cast<const uint8_t *>(&stats)[i]; + if (statsi < 1 || statsi > 9) { CHAR_LOG("Make new char error (invalid stat value: not between 1 to 9): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n"_fmt, s, sd->account_id, slot, name, - stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], - stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5], + stats.str, stats.agi, stats.vit, stats.int_, stats.dex, stats.luk, + stats.str + stats.agi + stats.vit + stats.int_ + stats.dex + stats.luk, hair_style, hair_color); return nullptr; } @@ -708,8 +724,8 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui { CHAR_LOG("Make new char error (name already exists): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n"_fmt, s, sd->account_id, slot, name, cd.key.name, - stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], - stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5], + stats.str, stats.agi, stats.vit, stats.int_, stats.dex, stats.luk, + stats.str + stats.agi + stats.vit + stats.int_ + stats.dex + stats.luk, hair_style, hair_color); return nullptr; } @@ -718,8 +734,8 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui { CHAR_LOG("Make new char error (slot already used): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n"_fmt, s, sd->account_id, slot, name, cd.key.name, - stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], - stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5], + stats.str, stats.agi, stats.vit, stats.int_, stats.dex, stats.luk, + stats.str + stats.agi + stats.vit + stats.int_ + stats.dex + stats.luk, hair_style, hair_color); return nullptr; } @@ -729,8 +745,8 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui { CHAR_LOG("Make new char error (name used is wisp name for server): (connection #%d, account: %d) slot %d, name: %s (actual name whisper server: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n"_fmt, s, sd->account_id, slot, name, wisp_server_name, - stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], - stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5], + stats.str, stats.agi, stats.vit, stats.int_, stats.dex, stats.luk, + stats.str + stats.agi + stats.vit + stats.int_ + stats.dex + stats.luk, hair_style, hair_color); return nullptr; } @@ -739,8 +755,8 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui CHAR_LOG("Creation of New Character: (connection #%d, account: %d) slot %d, character Name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d. [%s]\n"_fmt, s, sd->account_id, slot, name, - stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], - stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5], + stats.str, stats.agi, stats.vit, stats.int_, stats.dex, stats.luk, + stats.str + stats.agi + stats.vit + stats.int_ + stats.dex + stats.luk, hair_style, hair_color, ip); CharPair cp; @@ -757,12 +773,12 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui cd.base_exp = 0; cd.job_exp = 0; cd.zeny = 0; - cd.attrs[ATTR::STR] = stats[0]; - cd.attrs[ATTR::AGI] = stats[1]; - cd.attrs[ATTR::VIT] = stats[2]; - cd.attrs[ATTR::INT] = stats[3]; - cd.attrs[ATTR::DEX] = stats[4]; - cd.attrs[ATTR::LUK] = stats[5]; + cd.attrs[ATTR::STR] = stats.str; + cd.attrs[ATTR::AGI] = stats.agi; + cd.attrs[ATTR::VIT] = stats.vit; + cd.attrs[ATTR::INT] = stats.int_; + cd.attrs[ATTR::DEX] = stats.dex; + cd.attrs[ATTR::LUK] = stats.luk; cd.max_hp = 40 * (100 + cd.attrs[ATTR::VIT]) / 100; cd.max_sp = 11 * (100 + cd.attrs[ATTR::INT]) / 100; cd.hp = cd.max_hp; @@ -963,66 +979,69 @@ int mmo_char_send006b(Session *s, struct char_session_data *sd) } } - const int offset = 24; - WFIFO_ZERO(s, 0, offset + found_num * 106); - WFIFOW(s, 0) = 0x6b; - WFIFOW(s, 2) = offset + found_num * 106; + Packet_Head<0x006b> head_6b; + std::vector<Packet_Repeat<0x006b>> repeat_6b; + + head_6b.unused = {}; for (int i = 0; i < found_num; i++) { const CharPair *cp = found_char[i]; - int j = offset + (i * 106); const CharKey *k = &cp->key; const CharData *p = cp->data.get(); - WFIFOL(s, j) = unwrap<CharId>(k->char_id); - WFIFOL(s, j + 4) = p->base_exp; - WFIFOL(s, j + 8) = p->zeny; - WFIFOL(s, j + 12) = p->job_exp; - WFIFOL(s, j + 16) = p->job_level; - - WFIFOW(s, j + 20) = unwrap<ItemNameId>(find_equip_view(cp, EPOS::SHOES)); - WFIFOW(s, j + 22) = unwrap<ItemNameId>(find_equip_view(cp, EPOS::GLOVES)); - WFIFOW(s, j + 24) = unwrap<ItemNameId>(find_equip_view(cp, EPOS::CAPE)); - WFIFOW(s, j + 26) = unwrap<ItemNameId>(find_equip_view(cp, EPOS::MISC1)); - WFIFOL(s, j + 28) = static_cast<uint16_t>(p->option); - - WFIFOL(s, j + 32) = p->karma; - WFIFOL(s, j + 36) = p->manner; - - WFIFOW(s, j + 40) = p->status_point; - WFIFOW(s, j + 42) = std::min(p->hp, 0x7fff); - WFIFOW(s, j + 44) = std::min(p->max_hp, 0x7fff); - WFIFOW(s, j + 46) = std::min(p->sp, 0x7fff); - WFIFOW(s, j + 48) = std::min(p->max_sp, 0x7fff); - WFIFOW(s, j + 50) = static_cast<uint16_t>(DEFAULT_WALK_SPEED.count()); // p->speed; - WFIFOW(s, j + 52) = unwrap<Species>(p->species); - WFIFOW(s, j + 54) = p->hair; -// WFIFOW(s,j+56) = p->weapon; // dont send weapon since TMW does not support it - WFIFOW(s, j + 56) = 0; - WFIFOW(s, j + 58) = p->base_level; - WFIFOW(s, j + 60) = p->skill_point; - WFIFOW(s, j + 62) = unwrap<ItemNameId>(p->head_bottom); - WFIFOW(s, j + 64) = unwrap<ItemNameId>(p->shield); - WFIFOW(s, j + 66) = unwrap<ItemNameId>(p->head_top); - WFIFOW(s, j + 68) = unwrap<ItemNameId>(p->head_mid); - WFIFOW(s, j + 70) = p->hair_color; - WFIFOW(s, j + 72) = unwrap<ItemNameId>(find_equip_view(cp, EPOS::MISC2)); -// WFIFOW(s,j+72) = p->clothes_color; - - WFIFO_STRING(s, j + 74, k->name.to__actual(), 24); - - WFIFOB(s, j + 98) = saturate<uint8_t>(p->attrs[ATTR::STR]); - WFIFOB(s, j + 99) = saturate<uint8_t>(p->attrs[ATTR::AGI]); - WFIFOB(s, j + 100) = saturate<uint8_t>(p->attrs[ATTR::VIT]); - WFIFOB(s, j + 101) = saturate<uint8_t>(p->attrs[ATTR::INT]); - WFIFOB(s, j + 102) = saturate<uint8_t>(p->attrs[ATTR::DEX]); - WFIFOB(s, j + 103) = saturate<uint8_t>(p->attrs[ATTR::LUK]); - WFIFOB(s, j + 104) = k->char_num; + Packet_Repeat<0x006b> info; + CharSelect& sel = info.char_select; + + sel.char_id = k->char_id; + sel.base_exp = p->base_exp; + sel.zeny = p->zeny; + sel.job_exp = p->job_exp; + sel.job_level = p->job_level; + + sel.shoes = find_equip_view(cp, EPOS::SHOES); + sel.gloves = find_equip_view(cp, EPOS::GLOVES); + sel.cape = find_equip_view(cp, EPOS::CAPE); + sel.misc1 = find_equip_view(cp, EPOS::MISC1); + sel.option = p->option; + + sel.karma = p->karma; + sel.manner = p->manner; + + sel.status_point = p->status_point; + sel.hp = std::min(p->hp, 0x7fff); + sel.max_hp = std::min(p->max_hp, 0x7fff); + sel.sp = std::min(p->sp, 0x7fff); + sel.max_sp = std::min(p->max_sp, 0x7fff); + sel.speed = static_cast<uint16_t>(DEFAULT_WALK_SPEED.count()); // p->speed; + sel.species = p->species; + sel.hair_style = p->hair; + sel.weapon = 0; // p->weapon; // dont send weapon since TMW does not support it + sel.base_level = p->base_level; + sel.skill_point = p->skill_point; + sel.head_bottom = p->head_bottom; + sel.shield = p->shield; + sel.head_top = p->head_top; + sel.head_mid = p->head_mid; + sel.hair_color = p->hair_color; + sel.misc2 = find_equip_view(cp, EPOS::MISC2); // = p->clothes_color; + + sel.char_name = k->name; + + sel.stats.str = saturate<uint8_t>(p->attrs[ATTR::STR]); + sel.stats.agi = saturate<uint8_t>(p->attrs[ATTR::AGI]); + sel.stats.vit = saturate<uint8_t>(p->attrs[ATTR::VIT]); + sel.stats.int_ = saturate<uint8_t>(p->attrs[ATTR::INT]); + sel.stats.dex = saturate<uint8_t>(p->attrs[ATTR::DEX]); + sel.stats.luk = saturate<uint8_t>(p->attrs[ATTR::LUK]); + sel.char_num = k->char_num; + sel.unused = 0; + + repeat_6b.push_back(info); } - WFIFOSET(s, WFIFOW(s, 2)); + send_vpacket<0x006b, 24, 106>(s, head_6b, repeat_6b); return 0; } @@ -1052,8 +1071,6 @@ int set_account_reg2(AccountId acc, Slice<global_reg> reg) static int char_divorce(CharPair *cp) { - uint8_t buf[10]; - if (cp == NULL) return 0; @@ -1062,24 +1079,31 @@ int char_divorce(CharPair *cp) if (!cs->partner_id) { - WBUFW(buf, 0) = 0x2b12; - WBUFL(buf, 2) = unwrap<CharId>(ck->char_id); + Packet_Fixed<0x2b12> fixed_12; + fixed_12.char_id = ck->char_id; // partner id 0 means failure - WBUFL(buf, 6) = unwrap<CharId>(cs->partner_id); - mapif_sendall(buf, 10); + fixed_12.partner_id = cs->partner_id; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b12, 10>(ss, fixed_12); + } return 0; } - WBUFW(buf, 0) = 0x2b12; - WBUFL(buf, 2) = unwrap<CharId>(ck->char_id); + Packet_Fixed<0x2b12> fixed_12; + fixed_12.char_id = ck->char_id; for (CharPair& cd : char_keys) { if (cd.key.char_id == cs->partner_id && cd.data->partner_id == ck->char_id) { - WBUFL(buf, 6) = unwrap<CharId>(cs->partner_id); - mapif_sendall(buf, 10); + fixed_12.partner_id = cs->partner_id; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b12, 10>(ss, fixed_12); + } + cs->partner_id = CharId(); cd.data->partner_id = CharId(); return 0; @@ -1088,17 +1112,24 @@ int char_divorce(CharPair *cp) // Don't worry about this, as the map server should verify itself that the other doesn't have us as a partner, and so won't mess with their marriage else if (cd.key.char_id == cs->partner_id) { - WBUFL(buf, 6) = unwrap<CharId>(cs->partner_id); - mapif_sendall(buf, 10); + fixed_12.partner_id = cs->partner_id; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b12, 10>(ss, fixed_12); + } + cs->partner_id = CharId(); return 0; } } // Our partner wasn't found, so just clear our marriage - WBUFL(buf, 6) = unwrap<CharId>(cs->partner_id); + fixed_12.partner_id = cs->partner_id; cs->partner_id = CharId(); - mapif_sendall(buf, 10); + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b12, 10>(ss, fixed_12); + } return 0; } @@ -1143,10 +1174,12 @@ int char_delete(CharPair *cp) // Force the character (and all on the same account) to leave all map servers { - unsigned char buf[6]; - WBUFW(buf, 0) = 0x2afe; - WBUFL(buf, 2) = unwrap<AccountId>(ck->account_id); - mapif_sendall(buf, 6); + Packet_Fixed<0x2afe> fixed_fe; + fixed_fe.account_id = ck->account_id; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2afe, 6>(ss, fixed_fe); + } } return 0; @@ -1165,14 +1198,20 @@ void parse_tologin(Session *ls) char_session_data *sd = static_cast<char_session_data *>(ls->session_data.get()); - while (RFIFOREST(ls) >= 2) + RecvResult rv = RecvResult::Complete; + uint16_t packet_id; + while (rv == RecvResult::Complete && packet_peek_id(ls, &packet_id)) { - switch (RFIFOW(ls, 0)) + switch (packet_id) { case 0x2711: - if (RFIFOREST(ls) < 3) - return; - if (RFIFOB(ls, 2)) + { + Packet_Fixed<0x2711> fixed; + rv = recv_fpacket<0x2711, 3>(ls, fixed); + if (rv != RecvResult::Complete) + break; + + if (fixed.code) { PRINTF("Can not connect to login-server.\n"_fmt); PRINTF("The server communication passwords (default s1/p1) is probably invalid.\n"_fmt); @@ -1187,62 +1226,72 @@ void parse_tologin(Session *ls) // if no map-server already connected, display a message... int i; for (i = 0; i < MAX_MAP_SERVERS; i++) + { if (server_session[i] && server[i].maps[0]) // if map-server online and at least 1 map break; + } if (i == MAX_MAP_SERVERS) PRINTF("Awaiting maps from map-server.\n"_fmt); } - RFIFOSKIP(ls, 3); break; + } case 0x2713: - if (RFIFOREST(ls) < 51) - return; + { + Packet_Fixed<0x2713> fixed; + rv = recv_fpacket<0x2713, 51>(ls, fixed); + if (rv != RecvResult::Complete) + break; + for (io::FD i : iter_fds()) { - AccountId acc = wrap<AccountId>(RFIFOL(ls, 2)); + AccountId acc = fixed.account_id; Session *s2 = get_session(i); if (!s2) continue; sd = static_cast<char_session_data *>(s2->session_data.get()); if (sd && sd->account_id == acc) { - if (RFIFOB(ls, 6) != 0) + if (fixed.invalid != 0) { - WFIFOW(s2, 0) = 0x6c; - WFIFOB(s2, 2) = 0x42; - WFIFOSET(s2, 3); + Packet_Fixed<0x006c> fixed_6c; + fixed_6c.code = 0x42; + send_fpacket<0x006c, 3>(s2, fixed_6c); } else if (max_connect_user == 0 || count_users() < max_connect_user) { - sd->email = stringish<AccountEmail>(RFIFO_STRING<40>(ls, 7)); + sd->email = stringish<AccountEmail>(fixed.email); if (!e_mail_check(sd->email)) sd->email = DEFAULT_EMAIL; - sd->connect_until_time = static_cast<time_t>(RFIFOL(ls, 47)); + sd->connect_until_time = fixed.connect_until; // send characters to player mmo_char_send006b(s2, sd); } else { // refuse connection: too much online players - WFIFOW(s2, 0) = 0x6c; - WFIFOB(s2, 2) = 0; - WFIFOSET(s2, 3); + Packet_Fixed<0x006c> fixed_6c; + fixed_6c.code = 0; + send_fpacket<0x006c, 3>(s2, fixed_6c); } break; } } - RFIFOSKIP(ls, 51); break; + } // Receiving of an e-mail/time limit from the login-server (answer of a request because a player comes back from map-server to char-server) by [Yor] case 0x2717: - if (RFIFOREST(ls) < 50) - return; + { + Packet_Fixed<0x2717> fixed; + rv = recv_fpacket<0x2717, 50>(ls, fixed); + if (rv != RecvResult::Complete) + break; + for (io::FD i : iter_fds()) { - AccountId acc = wrap<AccountId>(RFIFOL(ls, 2)); + AccountId acc = fixed.account_id; Session *s2 = get_session(i); if (!s2) continue; @@ -1251,40 +1300,49 @@ void parse_tologin(Session *ls) { if (sd->account_id == acc) { - sd->email = stringish<AccountEmail>(RFIFO_STRING<40>(ls, 6)); + sd->email = fixed.email; if (!e_mail_check(sd->email)) sd->email = DEFAULT_EMAIL; - sd->connect_until_time = static_cast<time_t>(RFIFOL(ls, 46)); + sd->connect_until_time = fixed.connect_until; break; } } } - RFIFOSKIP(ls, 50); break; + } case 0x2721: // gm reply - if (RFIFOREST(ls) < 10) - return; + { + Packet_Fixed<0x2721> fixed; + rv = recv_fpacket<0x2721, 10>(ls, fixed); + if (rv != RecvResult::Complete) + break; + { - AccountId acc = wrap<AccountId>(RFIFOL(ls, 2)); - GmLevel gml = GmLevel::from(RFIFOL(ls, 2)); - unsigned char buf[10]; - WBUFW(buf, 0) = 0x2b0b; - WBUFL(buf, 2) = unwrap<AccountId>(acc); - WBUFL(buf, 6) = gml.get_all_bits(); - mapif_sendall(buf, 10); + AccountId acc = fixed.account_id; + GmLevel gml = fixed.gm_level; + + Packet_Fixed<0x2b0b> fixed_2b; + fixed_2b.account_id = acc; + fixed_2b.gm_level = gml; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b0b, 10>(ss, fixed_2b); + } } - RFIFOSKIP(ls, 10); break; + } case 0x2723: // changesex reply (modified by [Yor]) - if (RFIFOREST(ls) < 7) - return; + { + Packet_Fixed<0x2723> fixed; + rv = recv_fpacket<0x2723, 7>(ls, fixed); + if (rv != RecvResult::Complete) + break; + { - unsigned char buf[7]; - AccountId acc = wrap<AccountId>(RFIFOL(ls, 2)); - SEX sex = static_cast<SEX>(RFIFOB(ls, 6)); - RFIFOSKIP(ls, 7); + AccountId acc = fixed.account_id; + SEX sex = fixed.sex; if (acc) { for (CharPair& cp : char_keys) @@ -1312,18 +1370,26 @@ void parse_tologin(Session *ls) // disconnect player if online on char-server disconnect_player(acc); } - WBUFW(buf, 0) = 0x2b0d; - WBUFL(buf, 2) = unwrap<AccountId>(acc); - WBUFB(buf, 6) = static_cast<uint8_t>(sex); - mapif_sendall(buf, 7); + Packet_Fixed<0x2b0d> fixed_0d; + fixed_0d.account_id = acc; + fixed_0d.sex = sex; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b0d, 7>(ss, fixed_0d); + } } break; + } case 0x2726: // Request to send a broadcast message (no answer) - if (RFIFOREST(ls) < 8 - || RFIFOREST(ls) < (8 + RFIFOL(ls, 4))) - return; - if (RFIFOL(ls, 4) < 1) + { + Packet_Head<0x2726> head; + AString repeat; + rv = recv_vpacket<0x2726, 8, 1>(ls, head, repeat); + if (rv != RecvResult::Complete) + break; + + if (!repeat) CHAR_LOG("Receiving a message for broadcast, but message is void.\n"_fmt); else { @@ -1336,8 +1402,7 @@ void parse_tologin(Session *ls) CHAR_LOG("'ladmin': Receiving a message for broadcast, but no map-server is online.\n"_fmt); else { - size_t len = RFIFOL(ls, 4); - AString message = RFIFO_STRING(ls, 8, len).to_print().lstrip(); + AString message = repeat.to_print().lstrip(); // if message is only composed of spaces if (!message) CHAR_LOG("Receiving a message for broadcast, but message is only a lot of spaces.\n"_fmt); @@ -1347,62 +1412,81 @@ void parse_tologin(Session *ls) CHAR_LOG("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n"_fmt, message); // send broadcast to all map-servers - uint8_t buf[4 + len]; - WBUFW(buf, 0) = 0x3800; - WBUFW(buf, 2) = 4 + len; - WBUF_STRING(buf, 4, message, len); - mapif_sendall(buf, WBUFW(buf, 2)); + for (Session *ss : iter_map_sessions()) + { + send_packet_repeatonly<0x3800, 4, 1>(ss, message); + } } } } - RFIFOSKIP(ls, 8 + RFIFOL(ls, 4)); break; + } // account_reg2変更通知 case 0x2729: - if (RFIFOREST(ls) < 4 || RFIFOREST(ls) < RFIFOW(ls, 2)) - return; + { + Packet_Head<0x2729> head; + std::vector<Packet_Repeat<0x2729>> repeat; + rv = recv_vpacket<0x2729, 8, 36>(ls, head, repeat); + if (rv != RecvResult::Complete) + break; + { Array<struct global_reg, ACCOUNT_REG2_NUM> reg; - int j, p; - AccountId acc = wrap<AccountId>(RFIFOL(ls, 4)); - for (p = 8, j = 0; - p < RFIFOW(ls, 2) && j < ACCOUNT_REG2_NUM; - p += 36, j++) + int j = 0; + AccountId acc = head.account_id; + for (const auto& info : repeat) { - reg[j].str = stringish<VarName>(RFIFO_STRING<32>(ls, p)); - reg[j].value = RFIFOL(ls, p + 32); + reg[j].str = info.name; + reg[j].value = info.value; + ++j; + if (j == ACCOUNT_REG2_NUM) + break; } set_account_reg2(acc, Slice<struct global_reg>(reg.begin(), j)); - size_t len = RFIFOW(ls, 2); - uint8_t buf[len]; - RFIFO_BUF_CLONE(ls, buf, len); - WBUFW(buf, 0) = 0x2b11; - mapif_sendall(buf, len); + Packet_Head<0x2b11> head_11; + head_11.account_id = head.account_id; + std::vector<Packet_Repeat<0x2b11>> repeat_11(repeat.size()); + for (size_t k = 0; k < repeat.size(); ++k) + { + repeat_11[k].name = repeat[k].name; + repeat_11[k].value = repeat[k].value; + } + for (Session *ss : iter_map_sessions()) + { + send_vpacket<0x2b11, 8, 36>(ss, head_11, repeat_11); + } } - RFIFOSKIP(ls, RFIFOW(ls, 2)); break; + } case 0x7924: { // [Fate] Itemfrob package: forwarded from login-server - if (RFIFOREST(ls) < 10) - return; - ItemNameId source_id = wrap<ItemNameId>(RFIFOL(ls, 2)); - ItemNameId dest_id = wrap<ItemNameId>(RFIFOL(ls, 6)); - unsigned char buf[10]; + Packet_Fixed<0x7924> fixed; + rv = recv_fpacket<0x7924, 10>(ls, fixed); + if (rv != RecvResult::Complete) + break; + + ItemNameId source_id = fixed.source_item_id; + ItemNameId dest_id = fixed.dest_item_id; - WBUFW(buf, 0) = 0x2afa; - WBUFL(buf, 2) = unwrap<ItemNameId>(source_id); - WBUFL(buf, 6) = unwrap<ItemNameId>(dest_id); + Packet_Fixed<0x2afa> fixed_fa; + fixed_fa.source_item_id = source_id; + fixed_fa.dest_item_id = dest_id; + + // forward package to map servers + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2afa, 10>(ss, fixed_fa); + } - mapif_sendall(buf, 10); // forward package to map servers for (CharPair& cp : char_keys) { CharKey *k = &cp.key; CharData& cd = *cp.data.get(); CharData *c = &cd; - struct storage *s = account2storage(k->account_id); + Storage *s = account2storage(k->account_id); int changes = 0; int j; #define FIX(v) if (v == source_id) {v = dest_id; ++changes; } @@ -1428,16 +1512,18 @@ void parse_tologin(Session *ls) mmo_char_sync(); inter_storage_save(); - RFIFOSKIP(ls, 10); break; } // Account deletion notification (from login-server) case 0x2730: - if (RFIFOREST(ls) < 6) - return; { - AccountId aid = wrap<AccountId>(RFIFOL(ls, 2)); + Packet_Fixed<0x2730> fixed; + rv = recv_fpacket<0x2730, 6>(ls, fixed); + if (rv != RecvResult::Complete) + break; + + AccountId aid = fixed.account_id; // Deletion of all characters of the account //#warning "This comment is a lie, but it's still true." @@ -1468,50 +1554,57 @@ void parse_tologin(Session *ls) inter_storage_delete(aid); // send to all map-servers to disconnect the player { - unsigned char buf[6]; - WBUFW(buf, 0) = 0x2b13; - WBUFL(buf, 2) = unwrap<AccountId>(aid); - mapif_sendall(buf, 6); + Packet_Fixed<0x2b13> fixed_13; + fixed_13.account_id = aid; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b13, 6>(ss, fixed_13); + } } // disconnect player if online on char-server disconnect_player(aid); - } - RFIFOSKIP(ls, 6); break; + } // State change of account/ban notification (from login-server) by [Yor] case 0x2731: - if (RFIFOREST(ls) < 11) - return; { - AccountId aid = wrap<AccountId>(RFIFOL(ls, 2)); + Packet_Fixed<0x2731> fixed; + rv = recv_fpacket<0x2731, 11>(ls, fixed); + if (rv != RecvResult::Complete) + break; + + AccountId aid = fixed.account_id; // send to all map-servers to disconnect the player { - unsigned char buf[11]; - WBUFW(buf, 0) = 0x2b14; - WBUFL(buf, 2) = unwrap<AccountId>(aid); - WBUFB(buf, 6) = RFIFOB(ls, 6); // 0: change of statut, 1: ban - WBUFL(buf, 7) = RFIFOL(ls, 7); // status or final date of a banishment - mapif_sendall(buf, 11); + Packet_Fixed<0x2b14> fixed_14; + fixed_14.account_id = aid; + fixed_14.ban_not_status = fixed.ban_not_status; // 0: change of statut, 1: ban + fixed_14.status_or_ban_until = fixed.status_or_ban_until; // status or final date of a banishment + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b14, 11>(ss, fixed_14); + } } // disconnect player if online on char-server disconnect_player(aid); - } - RFIFOSKIP(ls, 11); break; + } // Receiving GM acounts info from login-server (by [Yor]) case 0x2732: - if (RFIFOREST(ls) < 4 || RFIFOREST(ls) < RFIFOW(ls, 2)) - return; + { + std::vector<Packet_Repeat<0x2732>> repeat; + rv = recv_packet_repeatonly<0x2732, 4, 5>(ls, repeat); + if (rv != RecvResult::Complete) + break; + { - size_t len = RFIFOW(ls, 2); - uint8_t buf[len]; - gm_accounts.clear(); - gm_accounts.reserve((len - 4) / 5); - for (int i = 4; i < len; i += 5) + gm_accounts.resize(repeat.size()); + for (size_t k = 0; k < repeat.size(); ++k) { - gm_accounts.push_back({wrap<AccountId>(RFIFOL(ls, i)), GmLevel::from(static_cast<uint32_t>(RFIFOB(ls, i + 4)))}); + gm_accounts[k].account_id = repeat[k].account_id; + gm_accounts[k].level = repeat[k].gm_level; } PRINTF("From login-server: receiving of %zu GM accounts information.\n"_fmt, gm_accounts.size()); @@ -1519,19 +1612,30 @@ void parse_tologin(Session *ls) gm_accounts.size()); create_online_files(); // update online players files (perhaps some online players change of GM level) // send new gm acccounts level to map-servers - RFIFO_BUF_CLONE(ls, buf, len); - WBUFW(buf, 0) = 0x2b15; - mapif_sendall(buf, len); + std::vector<Packet_Repeat<0x2b15>> repeat_15(repeat.size()); + for (size_t k = 0; k < repeat.size(); ++k) + { + repeat_15[k].account_id = repeat[k].account_id; + repeat_15[k].gm_level = repeat[k].gm_level; + } + for (Session *ss : iter_map_sessions()) + { + send_packet_repeatonly<0x2b15, 4, 5>(ss, repeat_15); + } } - RFIFOSKIP(ls, RFIFOW(ls, 2)); break; + } case 0x2741: // change password reply - if (RFIFOREST(ls) < 7) - return; + { + Packet_Fixed<0x2741> fixed; + rv = recv_fpacket<0x2741, 7>(ls, fixed); + if (rv != RecvResult::Complete) + break; + { - AccountId acc = wrap<AccountId>(RFIFOL(ls, 2)); - int status = RFIFOB(ls, 6); + AccountId acc = fixed.account_id; + int status = fixed.status; for (io::FD i : iter_fds()) { @@ -1543,20 +1647,22 @@ void parse_tologin(Session *ls) { if (sd->account_id == acc) { - WFIFOW(s2, 0) = 0x62; - WFIFOB(s2, 2) = status; - WFIFOSET(s2, 3); + Packet_Fixed<0x0062> fixed_62; + fixed_62.status = status; + send_fpacket<0x0062, 3>(s2, fixed_62); break; } } } } - RFIFOSKIP(ls, 7); break; + } default: + { ls->set_eof(); return; + } } } } @@ -1598,47 +1704,60 @@ void parse_frommap(Session *ms) return; } - while (RFIFOREST(ms) >= 2) + RecvResult rv = RecvResult::Complete; + uint16_t packet_id; + while (rv == RecvResult::Complete && packet_peek_id(ms, &packet_id)) { - switch (RFIFOW(ms, 0)) + switch (packet_id) { // request from map-server to reload GM accounts. Transmission to login-server (by Yor) case 0x2af7: + { + Packet_Fixed<0x2af7> fixed; + rv = recv_fpacket<0x2af7, 2>(ms, fixed); + if (rv != RecvResult::Complete) + break; + if (login_session) { // don't send request if no login-server - WFIFOW(login_session, 0) = 0x2709; - WFIFOSET(login_session, 2); + Packet_Fixed<0x2709> fixed_09; + send_fpacket<0x2709, 2>(login_session, fixed_09); } - RFIFOSKIP(ms, 2); break; + } // Receiving map names list from the map-server case 0x2afa: - if (RFIFOREST(ms) < 4 || RFIFOREST(ms) < RFIFOW(ms, 2)) - return; { + std::vector<Packet_Repeat<0x2afa>> repeat; + rv = recv_packet_repeatonly<0x2afa, 4, 16>(ms, repeat); + if (rv != RecvResult::Complete) + break; + for (MapName &foo : server[id].maps) foo = MapName(); - int j = 0; - for (int i = 4; i < RFIFOW(ms, 2); i += 16) + + for (size_t j = 0; j < repeat.size(); ++j) { - server[id].maps[j] = RFIFO_STRING<16>(ms, i); - j++; + server[id].maps[j] = repeat[j].map_name; } + const size_t j = repeat.size(); + { - PRINTF("Map-Server %d connected: %d maps, from IP %s port %d.\n"_fmt, + PRINTF("Map-Server %d connected: %zu maps, from IP %s port %d.\n"_fmt, id, j, server[id].ip, server[id].port); PRINTF("Map-server %d loading complete.\n"_fmt, id); - CHAR_LOG("Map-Server %d connected: %d maps, from IP %s port %d. Map-server %d loading complete.\n"_fmt, + CHAR_LOG("Map-Server %d connected: %zu maps, from IP %s port %d. Map-server %d loading complete.\n"_fmt, id, j, server[id].ip, server[id].port, id); } - WFIFOW(ms, 0) = 0x2afb; - WFIFOB(ms, 2) = 0; - WFIFO_STRING(ms, 3, wisp_server_name.to__actual(), 24); - WFIFOSET(ms, 27); + + Packet_Fixed<0x2afb> fixed_fb; + fixed_fb.unknown = 0; + fixed_fb.whisper_name = wisp_server_name; + send_fpacket<0x2afb, 27>(ms, fixed_fb); + { - unsigned char buf[16384]; if (j == 0) { PRINTF("WARNING: Map-Server %d have NO map.\n"_fmt, id); @@ -1648,49 +1767,62 @@ void parse_frommap(Session *ms) } else { - WBUFW(buf, 0) = 0x2b04; - WBUFW(buf, 2) = j * 16 + 10; - WBUFIP(buf, 4) = server[id].ip; - WBUFW(buf, 8) = server[id].port; - // server[id].maps[i] = RFIFO_STRING(fd, 4 + i * 16) + Packet_Head<0x2b04> head_04; + head_04.ip = server[id].ip; + head_04.port = server[id].port; + std::vector<Packet_Repeat<0x2b04>> repeat_04(j); for (int i = 0; i < j; ++i) - WBUF_STRING(buf, 10, server[id].maps[i], 16); - mapif_sendallwos(ms, buf, WBUFW(buf, 2)); + { + repeat_04[i].map_name = server[id].maps[i]; + } + for (Session *ss : iter_map_sessions()) + { + if (ss == ms) + continue; + send_vpacket<0x2b04, 10, 16>(ss, head_04, repeat_04); + } } // Transmitting the maps of the other map-servers to the new map-server for (int x = 0; x < MAX_MAP_SERVERS; x++) { if (server_session[x] && x != id) { - WFIFOW(ms, 0) = 0x2b04; - WFIFOIP(ms, 4) = server[x].ip; - WFIFOW(ms, 8) = server[x].port; - j = 0; + Packet_Head<0x2b04> head_04; + head_04.ip = server[x].ip; + head_04.port = server[x].port; + std::vector<Packet_Repeat<0x2b04>> repeat_04; for (int i = 0; i < MAX_MAP_PER_SERVER; i++) + { if (server[x].maps[i]) - WFIFO_STRING(ms, 10 + (j++) * 16, server[x].maps[i], 16); - if (j > 0) + { + Packet_Repeat<0x2b04> info; + info.map_name = server[x].maps[i]; + repeat_04.push_back(info); + } + } + if (repeat.size()) { - WFIFOW(ms, 2) = j * 16 + 10; - WFIFOSET(ms, WFIFOW(ms, 2)); + send_vpacket<0x2b04, 10, 16>(ms, head_04, repeat_04); } } } } - } - RFIFOSKIP(ms, RFIFOW(ms, 2)); break; + } // 認証要求 case 0x2afc: - if (RFIFOREST(ms) < 22) - return; { - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 2)); - CharId char_id = wrap<CharId>(RFIFOL(ms, 6)); - int login_id1 = RFIFOL(ms, 10); - int login_id2 = RFIFOL(ms, 14); - IP4Address ip = RFIFOIP(ms, 18); + Packet_Fixed<0x2afc> fixed; + rv = recv_fpacket<0x2afc, 22>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + AccountId account_id = fixed.account_id; + CharId char_id = fixed.char_id; + int login_id1 = fixed.login_id1; + int login_id2 = fixed.login_id2; + IP4Address ip = fixed.ip; for (AuthFifoEntry& afi : auth_fifo) { if (afi.account_id == account_id && @@ -1716,39 +1848,43 @@ void parse_frommap(Session *ms) CharData *cd = cp->data.get(); afi.delflag = 1; - WFIFOW(ms, 0) = 0x2afd; - WFIFOW(ms, 2) = 18 + sizeof(*ck) + sizeof(*cd); - WFIFOL(ms, 4) = unwrap<AccountId>(account_id); - WFIFOL(ms, 8) = afi.login_id2; - WFIFOL(ms, 12) = static_cast<time_t>(afi.connect_until_time); + Packet_Payload<0x2afd> payload_fd; // not file descriptor + payload_fd.account_id = account_id; + payload_fd.login_id2 = afi.login_id2; + payload_fd.connect_until = afi.connect_until_time; cd->sex = afi.sex; - WFIFOW(ms, 16) = afi.packet_tmw_version; + payload_fd.packet_tmw_version = afi.packet_tmw_version; FPRINTF(stderr, "From queue index %zd: recalling packet version %d\n"_fmt, (&afi - &auth_fifo.front()), afi.packet_tmw_version); - WFIFO_STRUCT(ms, 18, *ck); - WFIFO_STRUCT(ms, 18 + sizeof(*ck), *cd); - WFIFOSET(ms, WFIFOW(ms, 2)); + payload_fd.char_key = *ck; + payload_fd.char_data = *cd; + send_ppacket<0x2afd>(ms, payload_fd); goto x2afc_out; } } { - WFIFOW(ms, 0) = 0x2afe; - WFIFOL(ms, 2) = unwrap<AccountId>(account_id); - WFIFOSET(ms, 6); + Packet_Fixed<0x2afe> fixed_fe; + fixed_fe.account_id = account_id; + send_fpacket<0x2afe, 6>(ms, fixed_fe); PRINTF("auth_fifo search error! account %d not authentified.\n"_fmt, account_id); } - } x2afc_out: - RFIFOSKIP(ms, 22); break; + } // MAPサーバー上のユーザー数受信 case 0x2aff: - if (RFIFOREST(ms) < 6 || RFIFOREST(ms) < RFIFOW(ms, 2)) - return; - server[id].users = RFIFOW(ms, 4); + { + Packet_Head<0x2aff> head; + std::vector<Packet_Repeat<0x2aff>> repeat; + rv = recv_vpacket<0x2aff, 6, 4>(ms, head, repeat); + if (rv != RecvResult::Complete) + break; + + server[id].users = head.users; + assert (head.users == repeat.size()); if (anti_freeze_enable) server_freezeflag[id] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed // remove all previously online players of the server @@ -1761,7 +1897,7 @@ void parse_frommap(Session *ms) // add online players in the list by [Yor] for (int i = 0; i < server[id].users; i++) { - CharId char_id = wrap<CharId>(RFIFOL(ms, 6 + i * 4)); + CharId char_id = repeat[i].char_id; for (const CharPair& cd : char_keys) { if (cd.key.char_id == char_id) @@ -1779,313 +1915,370 @@ void parse_frommap(Session *ms) // only every 8 sec. (normally, 1 server send users every 5 sec.) Don't update every time, because that takes time, but only every 2 connection. // it set to 8 sec because is more than 5 (sec) and if we have more than 1 map-server, informations can be received in shifted. } - RFIFOSKIP(ms, RFIFOW(ms, 2)); break; + } // キャラデータ保存 case 0x2b01: - if (RFIFOREST(ms) < 4 || RFIFOREST(ms) < RFIFOW(ms, 2)) - return; { - AccountId aid = wrap<AccountId>(RFIFOL(ms, 4)); - CharId cid = wrap<CharId>(RFIFOL(ms, 8)); + Packet_Payload<0x2b01> payload; + rv = recv_ppacket<0x2b01>(ms, payload); + if (rv != RecvResult::Complete) + break; + + AccountId aid = payload.account_id; + CharId cid = payload.char_id; for (CharPair& cd : char_keys) { if (cd.key.account_id == aid && cd.key.char_id == cid) { - RFIFO_STRUCT(ms, 12, cd.key); - RFIFO_STRUCT(ms, 12 + sizeof(cd.key), *cd.data); + cd.key = payload.char_key; + *cd.data = payload.char_data; break; } } - } - RFIFOSKIP(ms, RFIFOW(ms, 2)); break; + } // キャラセレ要求 case 0x2b02: - if (RFIFOREST(ms) < 18) - return; { - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 2)); + Packet_Fixed<0x2b02> fixed; + rv = recv_fpacket<0x2b02, 18>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + AccountId account_id = fixed.account_id; if (auth_fifo_iter == auth_fifo.end()) auth_fifo_iter = auth_fifo.begin(); auth_fifo_iter->account_id = account_id; auth_fifo_iter->char_id = CharId(); - auth_fifo_iter->login_id1 = RFIFOL(ms, 6); - auth_fifo_iter->login_id2 = RFIFOL(ms, 10); + auth_fifo_iter->login_id1 = fixed.login_id1; + auth_fifo_iter->login_id2 = fixed.login_id2; auth_fifo_iter->delflag = 2; auth_fifo_iter->connect_until_time = TimeT(); // unlimited/unknown time by default (not display in map-server) - auth_fifo_iter->ip = RFIFOIP(ms, 14); + auth_fifo_iter->ip = fixed.ip; auth_fifo_iter++; - WFIFOW(ms, 0) = 0x2b03; - WFIFOL(ms, 2) = unwrap<AccountId>(account_id); - WFIFOB(ms, 6) = 0; - WFIFOSET(ms, 7); - } - RFIFOSKIP(ms, 18); + + Packet_Fixed<0x2b03> fixed_03; + fixed_03.account_id = account_id; + fixed_03.unknown = 0; + send_fpacket<0x2b03, 7>(ms, fixed_03); break; + } // マップサーバー間移動要求 case 0x2b05: - if (RFIFOREST(ms) < 49) - return; + { + Packet_Fixed<0x2b05> fixed; + rv = recv_fpacket<0x2b05, 49>(ms, fixed); + if (rv != RecvResult::Complete) + break; + if (auth_fifo_iter == auth_fifo.end()) auth_fifo_iter = auth_fifo.begin(); - RFIFO_WFIFO_CLONE(ms, ms, 44); - // overwrite - WFIFOW(ms, 0) = 0x2b06; - auth_fifo_iter->account_id = wrap<AccountId>(RFIFOL(ms, 2)); - auth_fifo_iter->char_id = wrap<CharId>(RFIFOL(ms, 14)); - auth_fifo_iter->login_id1 = RFIFOL(ms, 6); - auth_fifo_iter->login_id2 = RFIFOL(ms, 10); + Packet_Fixed<0x2b06> fixed_06; + fixed_06.account_id = fixed.account_id; + //fixed_06.error = fixed.login_id1; + //fixed_06.unknown = fixed.login_id2; + fixed_06.char_id = fixed.char_id; + fixed_06.map_name = fixed.map_name; + fixed_06.x = fixed.x; + fixed_06.y = fixed.y; + fixed_06.map_ip = fixed.map_ip; + fixed_06.map_port = fixed.map_port; + + auth_fifo_iter->account_id = fixed.account_id; + auth_fifo_iter->login_id1 = fixed.login_id1; + auth_fifo_iter->login_id2 = fixed.login_id2; + auth_fifo_iter->char_id = fixed.char_id; auth_fifo_iter->delflag = 0; - auth_fifo_iter->sex = static_cast<SEX>(RFIFOB(ms, 44)); + auth_fifo_iter->sex = fixed.sex; auth_fifo_iter->connect_until_time = TimeT(); // unlimited/unknown time by default (not display in map-server) - auth_fifo_iter->ip = RFIFOIP(ms, 45); + auth_fifo_iter->ip = fixed.client_ip; // default, if not found in the loop - WFIFOW(ms, 6) = 1; + fixed_06.error = 1; for (const CharPair& cd : char_keys) { - AccountId aid = wrap<AccountId>(RFIFOL(ms, 2)); - CharId cid = wrap<CharId>(RFIFOL(ms, 14)); + AccountId aid = fixed.account_id; + CharId cid = fixed.char_id; if (cd.key.account_id == aid && cd.key.char_id == cid) { auth_fifo_iter++; - WFIFOL(ms, 6) = 0; + fixed_06.error = 0; break; } } - WFIFOSET(ms, 44); - RFIFOSKIP(ms, 49); + send_fpacket<0x2b06, 44>(ms, fixed_06); break; + } // it is a request to become GM case 0x2b0a: - if (RFIFOREST(ms) < 4 || RFIFOREST(ms) < RFIFOW(ms, 2)) - return; { - int account_id = RFIFOL(ms, 4); + Packet_Head<0x2b0a> head; + AString repeat; + rv = recv_vpacket<0x2b0a, 8, 1>(ms, head, repeat); + if (rv != RecvResult::Complete) + break; + + AccountId account_id = head.account_id; if (login_session) { // don't send request if no login-server - size_t len = RFIFOW(ms, 2); - RFIFO_WFIFO_CLONE(ms, login_session, len); - WFIFOW(login_session, 0) = 0x2720; - WFIFOSET(login_session, len); + Packet_Head<0x2720> head_20; + head_20.account_id = account_id; + AString& repeat_20 = repeat; + send_vpacket<0x2720, 8, 1>(ms, head_20, repeat_20); } else { - WFIFOW(ms, 0) = 0x2b0b; - WFIFOL(ms, 2) = account_id; - WFIFOL(ms, 6) = 0; - WFIFOSET(ms, 10); + Packet_Fixed<0x2b0b> fixed_0b; + fixed_0b.account_id = account_id; + fixed_0b.gm_level = GmLevel(); + send_fpacket<0x2b0b, 10>(ms, fixed_0b); } - } - RFIFOSKIP(ms, RFIFOW(ms, 2)); break; + } // Map server send information to change an email of an account -> login-server case 0x2b0c: - if (RFIFOREST(ms) < 86) - return; + { + Packet_Fixed<0x2b0c> fixed; + rv = recv_fpacket<0x2b0c, 86>(ms, fixed); + if (rv != RecvResult::Complete) + break; + if (login_session) { // don't send request if no login-server - RFIFO_WFIFO_CLONE(ms, login_session, 86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B - WFIFOW(login_session, 0) = 0x2722; - WFIFOSET(login_session, 86); + Packet_Fixed<0x2722> fixed_22; + fixed_22.account_id = fixed.account_id; + fixed_22.old_email = fixed.old_email; + fixed_22.new_email = fixed.new_email; + send_fpacket<0x2722, 86>(login_session, fixed_22); } - RFIFOSKIP(ms, 86); break; + } // Map server ask char-server about a character name to do some operations (all operations are transmitted to login-server) case 0x2b0e: - if (RFIFOREST(ms) < 44) - return; + { + Packet_Fixed<0x2b0e> fixed; + rv = recv_fpacket<0x2b0e, 44>(ms, fixed); + if (rv != RecvResult::Complete) + break; + { - AccountId acc = wrap<AccountId>(RFIFOL(ms, 2)); // account_id of who ask (-1 if nobody) - CharName character_name = stringish<CharName>(RFIFO_STRING<24>(ms, 6)); - int operation = RFIFOW(ms, 30); + AccountId acc = fixed.account_id; + CharName character_name = fixed.char_name; + int operation = fixed.operation; // prepare answer - WFIFOW(ms, 0) = 0x2b0f; // answer - WFIFOL(ms, 2) = unwrap<AccountId>(acc); // who want do operation - WFIFOW(ms, 30) = operation; // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5-changesex + Packet_Fixed<0x2b0f> fixed_0f; + fixed_0f.account_id = acc; + fixed_0f.operation = operation; // search character const CharPair *cd = search_character(character_name); + // TODO invert the below logic to shrink this code + // Current logic: + // 1. if no character, return error 1 + // 2. else if gm level too low, return error 2 + // 3. else if login server offline, return error 3 + // 4. else return error 0 and maybe do other stuff if (cd) { const CharKey *ck = &cd->key; - WFIFO_STRING(ms, 6, ck->name.to__actual(), 24); // put correct name if found - WFIFOW(ms, 32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - switch (RFIFOW(ms, 30)) + fixed_0f.char_name = ck->name; + fixed_0f.error = 0; + switch (operation) { case 1: // block + { if (!acc || isGM(acc).overwhelms(isGM(ck->account_id))) { if (login_session) { // don't send request if no login-server - WFIFOW(login_session, 0) = 0x2724; - WFIFOL(login_session, 2) = unwrap<AccountId>(ck->account_id); // account value - WFIFOL(login_session, 6) = 5; // status of the account - WFIFOSET(login_session, 10); + Packet_Fixed<0x2724> fixed_24; + fixed_24.account_id = ck->account_id; + fixed_24.status = 5; + send_fpacket<0x2724, 10>(login_session, fixed_24); } else - WFIFOW(ms, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 3; } else - WFIFOW(ms, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 2; break; + } case 2: // ban + { if (!acc || isGM(acc).overwhelms(isGM(ck->account_id))) { if (login_session) { // don't send request if no login-server - WFIFOW(login_session, 0) = 0x2725; - WFIFOL(login_session, 2) = unwrap<AccountId>(ck->account_id); // account value - HumanTimeDiff ban_change; - RFIFO_STRUCT(ms, 32, ban_change); - WFIFO_STRUCT(login_session, 6, ban_change); - WFIFOSET(login_session, 18); + Packet_Fixed<0x2725> fixed_25; + fixed_25.account_id = ck->account_id; + HumanTimeDiff ban_change = fixed.ban_add; + fixed_25.ban_add = ban_change; + send_fpacket<0x2725, 18>(login_session, fixed_25); } else - WFIFOW(ms, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 3; } else - WFIFOW(ms, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 2; break; + } case 3: // unblock + { if (!acc || isGM(acc).overwhelms(isGM(ck->account_id))) { if (login_session) { // don't send request if no login-server - WFIFOW(login_session, 0) = 0x2724; - WFIFOL(login_session, 2) = unwrap<AccountId>(ck->account_id); // account value - WFIFOL(login_session, 6) = 0; // status of the account - WFIFOSET(login_session, 10); + Packet_Fixed<0x2724> fixed_24; + fixed_24.account_id = ck->account_id; + fixed_24.status = 0; + send_fpacket<0x2724, 10>(login_session, fixed_24); } else - WFIFOW(ms, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 3; } else - WFIFOW(ms, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 2; break; + } case 4: // unban + { if (!acc || isGM(acc).overwhelms(isGM(ck->account_id))) { if (login_session) { // don't send request if no login-server - WFIFOW(login_session, 0) = 0x272a; - WFIFOL(login_session, 2) = unwrap<AccountId>(ck->account_id); // account value - WFIFOSET(login_session, 6); + Packet_Fixed<0x272a> fixed_2a; + fixed_2a.account_id = ck->account_id; + send_fpacket<0x272a, 6>(login_session, fixed_2a); } else - WFIFOW(ms, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 3; } else - WFIFOW(ms, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 2; break; + } case 5: // changesex + { if (!acc || isGM(acc).overwhelms(isGM(ck->account_id))) { if (login_session) { // don't send request if no login-server - WFIFOW(login_session, 0) = 0x2727; - WFIFOL(login_session, 2) = unwrap<AccountId>(ck->account_id); // account value - WFIFOSET(login_session, 6); + Packet_Fixed<0x2727> fixed_27; + fixed_27.account_id = ck->account_id; + send_fpacket<0x2727, 6>(login_session, fixed_27); } else - WFIFOW(ms, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 3; } else - WFIFOW(ms, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.error = 2; break; + } } } else { // character name not found - WFIFO_STRING(ms, 6, character_name.to__actual(), 24); - WFIFOW(ms, 32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + fixed_0f.char_name = character_name; + fixed_0f.error = 1; } // send answer if a player ask, not if the server ask if (acc) { - WFIFOSET(ms, 34); + send_fpacket<0x2b0f, 34>(ms, fixed_0f); } - RFIFOSKIP(ms, 44); break; } - -// case 0x2b0f: not more used (available for futur usage) + } // account_reg保存要求 case 0x2b10: - if (RFIFOREST(ms) < 4 || RFIFOREST(ms) < RFIFOW(ms, 2)) - return; + { + Packet_Head<0x2b10> head; + std::vector<Packet_Repeat<0x2b10>> repeat; + rv = recv_vpacket<0x2b10, 8, 36>(ms, head, repeat); + if (rv != RecvResult::Complete) + break; + { Array<struct global_reg, ACCOUNT_REG2_NUM> reg; - int p, j; - AccountId acc = wrap<AccountId>(RFIFOL(ms, 4)); - for (p = 8, j = 0; - p < RFIFOW(ms, 2) && j < ACCOUNT_REG2_NUM; - p += 36, j++) + AccountId acc = head.account_id; + auto jlim = std::min(repeat.size(), ACCOUNT_REG2_NUM); + for (size_t j = 0; j < jlim; ++j) { - reg[j].str = stringish<VarName>(RFIFO_STRING<32>(ms, p)); - reg[j].value = RFIFOL(ms, p + 32); + reg[j].str = repeat[j].name; + reg[j].value = repeat[j].value; } - set_account_reg2(acc, Slice<struct global_reg>(reg.begin(), j)); + set_account_reg2(acc, Slice<struct global_reg>(reg.begin(), jlim)); // loginサーバーへ送る if (login_session) { // don't send request if no login-server - RFIFO_WFIFO_CLONE(ms, login_session, RFIFOW(ms, 2)); - WFIFOW(login_session, 0) = 0x2728; - WFIFOSET(login_session, WFIFOW(login_session, 2)); + Packet_Head<0x2728> head_28; + std::vector<Packet_Repeat<0x2728>> repeat_28(repeat.size()); + for (size_t j = 0; j < repeat.size(); ++j) + { + repeat_28[j].name = repeat[j].name; + repeat_28[j].value = repeat[j].value; + } + send_vpacket<0x2728, 8, 36>(login_session, head_28, repeat_28); } - RFIFOSKIP(ms, RFIFOW(ms, 2)); break; } + } // Map server is requesting a divorce case 0x2b16: - if (RFIFOREST(ms) < 4) - return; + { + Packet_Fixed<0x2b16> fixed; + rv = recv_fpacket<0x2b16, 6>(ms, fixed); + if (rv != RecvResult::Complete) + break; + { - CharId cid = wrap<CharId>(RFIFOL(ms, 2)); + CharId cid = fixed.char_id; for (CharPair& cd : char_keys) + { if (cd.key.char_id == cid) { char_divorce(&cd); break; } + } - RFIFOSKIP(ms, 6); break; } + } default: // inter server処理に渡す { - int r = inter_parse_frommap(ms); - if (r == 1) // 処理できた + RecvResult r = inter_parse_frommap(ms, packet_id); + if (r == RecvResult::Complete) break; - if (r == 2) // パケット長が足りない + if (r == RecvResult::Incomplete) return; - } // inter server処理でもない場合は切断 PRINTF("char: unknown packet 0x%04x (%zu bytes to read in buffer)! (from map).\n"_fmt, - RFIFOW(ms, 0), RFIFOREST(ms)); + packet_id, packet_avail(ms)); ms->set_eof(); return; + } } } } @@ -2164,25 +2357,27 @@ void handle_x0066(Session *s, struct char_session_data *sd, uint8_t rfifob_2, IP // if no map-server is connected, we send: server closed if (j == MAX_MAP_SERVERS) { - WFIFOW(s, 0) = 0x81; - WFIFOB(s, 2) = 1; // 01 = Server closed - WFIFOSET(s, 3); + Packet_Fixed<0x0081> fixed_81; + fixed_81.error_code = 1; + send_fpacket<0x0081, 3>(s, fixed_81); return; } } - WFIFOW(s, 0) = 0x71; - WFIFOL(s, 2) = unwrap<CharId>(ck->char_id); - WFIFO_STRING(s, 6, cd->last_point.map_, 16); + + Packet_Fixed<0x0071> fixed_71; + fixed_71.char_id = ck->char_id; + fixed_71.map_name = cd->last_point.map_; PRINTF("Character selection '%s' (account: %d, slot: %d) [%s]\n"_fmt, ck->name, sd->account_id, ck->char_num, ip); PRINTF("--Send IP of map-server. "_fmt); if (lan_ip_check(ip)) - WFIFOIP(s, 22) = lan_map_ip; + fixed_71.ip = lan_map_ip; else - WFIFOIP(s, 22) = server[i].ip; - WFIFOW(s, 26) = server[i].port; - WFIFOSET(s, 28); + fixed_71.ip = server[i].ip; + fixed_71.port = server[i].port; + send_fpacket<0x0071, 28>(s, fixed_71); + if (auth_fifo_iter == auth_fifo.end()) auth_fifo_iter = auth_fifo.begin(); auth_fifo_iter->account_id = sd->account_id; @@ -2216,36 +2411,40 @@ void parse_char(Session *s) char_session_data *sd = static_cast<char_session_data *>(s->session_data.get()); - while (RFIFOREST(s) >= 2) + RecvResult rv = RecvResult::Complete; + uint16_t packet_id; + while (rv == RecvResult::Complete && packet_peek_id(s, &packet_id)) { - switch (RFIFOW(s, 0)) + switch (packet_id) { - case 0x20b: //20040622暗号化ragexe対応 - if (RFIFOREST(s) < 19) - return; - RFIFOSKIP(s, 19); - break; - case 0x61: // change password request - if (RFIFOREST(s) < 50) - return; + { + Packet_Fixed<0x0061> fixed; + rv = recv_fpacket<0x0061, 50>(s, fixed); + if (rv != RecvResult::Complete) + break; + { - WFIFOW(login_session, 0) = 0x2740; - WFIFOL(login_session, 2) = unwrap<AccountId>(sd->account_id); - AccountPass old_pass = stringish<AccountPass>(RFIFO_STRING<24>(s, 2)); - WFIFO_STRING(login_session, 6, old_pass, 24); - AccountPass new_pass = stringish<AccountPass>(RFIFO_STRING<24>(s, 26)); - WFIFO_STRING(login_session, 30, new_pass, 24); - WFIFOSET(login_session, 54); + Packet_Fixed<0x2740> fixed_40; + fixed_40.account_id = sd->account_id; + AccountPass old_pass = fixed.old_pass; + fixed_40.old_pass = old_pass; + AccountPass new_pass = fixed.new_pass; + fixed_40.new_pass = new_pass; + send_fpacket<0x2740, 54>(login_session, fixed_40); } - RFIFOSKIP(s, 50); break; + } case 0x65: // 接続要求 - if (RFIFOREST(s) < 17) - return; + { + Packet_Fixed<0x0065> fixed; + rv = recv_fpacket<0x0065, 17>(s, fixed); + if (rv != RecvResult::Complete) + break; + { - AccountId account_id = wrap<AccountId>(RFIFOL(s, 2)); + AccountId account_id = fixed.account_id; GmLevel GM_value = isGM(account_id); if (GM_value) PRINTF("Account Logged On; Account ID: %d (GM level %d).\n"_fmt, @@ -2261,13 +2460,19 @@ void parse_char(Session *s) sd->connect_until_time = TimeT(); // unknow or illimited (not displaying on map-server) } sd->account_id = account_id; - sd->login_id1 = RFIFOL(s, 6); - sd->login_id2 = RFIFOL(s, 10); - sd->packet_tmw_version = RFIFOW(s, 14); - sd->sex = static_cast<SEX>(RFIFOB(s, 16)); + sd->login_id1 = fixed.login_id1; + sd->login_id2 = fixed.login_id2; + sd->packet_tmw_version = fixed.packet_tmw_version; + sd->sex = fixed.sex; // send back account_id - WFIFOL(s, 0) = unwrap<AccountId>(account_id); - WFIFOSET(s, 4); + // TODO put this into a proper packet + Little32 account_id_net; + if (!native_to_network(&account_id_net, account_id) + || !packet_send(s, reinterpret_cast<const Byte *>(&account_id_net), 4)) + { + s->set_eof(); + return; + } // search authentification for (AuthFifoEntry& afi : auth_fifo) { @@ -2285,9 +2490,9 @@ void parse_char(Session *s) if (login_session) { // don't send request if no login-server // request to login-server to obtain e-mail/time limit - WFIFOW(login_session, 0) = 0x2716; - WFIFOL(login_session, 2) = unwrap<AccountId>(sd->account_id); - WFIFOSET(login_session, 6); + Packet_Fixed<0x2716> fixed_16; + fixed_16.account_id = sd->account_id; + send_fpacket<0x2716, 6>(login_session, fixed_16); } // Record client version afi.packet_tmw_version = @@ -2298,9 +2503,9 @@ void parse_char(Session *s) else { // refuse connection (over populated) - WFIFOW(s, 0) = 0x6c; - WFIFOB(s, 2) = 0; - WFIFOSET(s, 3); + Packet_Fixed<0x006c> fixed_6c; + fixed_6c.code = 0; + send_fpacket<0x006c, 3>(s, fixed_6c); } goto x65_out; } @@ -2310,111 +2515,144 @@ void parse_char(Session *s) if (login_session) { // don't send request if no login-server - WFIFOW(login_session, 0) = 0x2712; // ask login-server to authentify an account - WFIFOL(login_session, 2) = unwrap<AccountId>(sd->account_id); - WFIFOL(login_session, 6) = sd->login_id1; - WFIFOL(login_session, 10) = sd->login_id2; // relate to the versions higher than 18 - WFIFOB(login_session, 14) = static_cast<uint8_t>(sd->sex); - WFIFOIP(login_session, 15) = s->client_ip; - WFIFOSET(login_session, 19); + Packet_Fixed<0x2712> fixed_12; + fixed_12.account_id = sd->account_id; + fixed_12.login_id1 = sd->login_id1; + fixed_12.login_id2 = sd->login_id2; // relate to the versions higher than 18 + fixed_12.sex = sd->sex; + fixed_12.ip = s->client_ip; + send_fpacket<0x2712, 19>(login_session, fixed_12); } else { // if no login-server, we must refuse connection - WFIFOW(s, 0) = 0x6c; - WFIFOB(s, 2) = 0; - WFIFOSET(s, 3); + Packet_Fixed<0x006c> fixed_6c; + fixed_6c.code = 0; + send_fpacket<0x006c, 3>(s, fixed_6c); } } } x65_out: - RFIFOSKIP(s, 17); break; + } case 0x66: // キャラ選択 - if (!sd || RFIFOREST(s) < 3) + { + Packet_Fixed<0x0066> fixed; + rv = recv_fpacket<0x0066, 3>(s, fixed); + if (rv != RecvResult::Complete) + break; + + if (!sd) + { + s->set_eof(); return; - handle_x0066(s, sd, RFIFOB(s, 2), ip); - RFIFOSKIP(s, 3); + } + handle_x0066(s, sd, fixed.code, ip); break; + } case 0x67: // 作成 - if (!sd || RFIFOREST(s) < 37) - return; { - CharName name = stringish<CharName>(RFIFO_STRING<24>(s, 2)); - uint8_t stats[6]; - for (int i = 0; i < 6; ++i) - stats[i] = RFIFOB(s, 26 + i); - uint8_t slot = RFIFOB(s, 32); - uint16_t hair_color = RFIFOW(s, 33); - uint16_t hair_style = RFIFOW(s, 35); + Packet_Fixed<0x0067> fixed; + rv = recv_fpacket<0x0067, 37>(s, fixed); + if (rv != RecvResult::Complete) + break; + + if (!sd) + { + s->set_eof(); + return; + } + CharName name = fixed.char_name; + Stats6 stats = fixed.stats; + uint8_t slot = fixed.slot; + uint16_t hair_color = fixed.hair_color; + uint16_t hair_style = fixed.hair_style; const CharPair *cp = make_new_char(s, name, stats, slot, hair_color, hair_style); if (!cp) { - WFIFOW(s, 0) = 0x6e; - WFIFOB(s, 2) = 0x00; - WFIFOSET(s, 3); - RFIFOSKIP(s, 37); + Packet_Fixed<0x006e> fixed_6e; + fixed_6e.code = 0x00; + send_fpacket<0x006e, 3>(s, fixed_6e); break; } const CharKey *ck = &cp->key; const CharData *cd = cp->data.get(); - WFIFOW(s, 0) = 0x6d; - WFIFO_ZERO(s, 2, 106); - - WFIFOL(s, 2) = unwrap<CharId>(ck->char_id); - WFIFOL(s, 2 + 4) = cd->base_exp; - WFIFOL(s, 2 + 8) = cd->zeny; - WFIFOL(s, 2 + 12) = cd->job_exp; - WFIFOL(s, 2 + 16) = cd->job_level; - - WFIFOL(s, 2 + 28) = cd->karma; - WFIFOL(s, 2 + 32) = cd->manner; - - WFIFOW(s, 2 + 40) = 0x30; - WFIFOW(s, 2 + 42) = saturate<int16_t>(cd->hp); - WFIFOW(s, 2 + 44) = saturate<int16_t>(cd->max_hp); - WFIFOW(s, 2 + 46) = saturate<int16_t>(cd->sp); - WFIFOW(s, 2 + 48) = saturate<int16_t>(cd->max_sp); - WFIFOW(s, 2 + 50) = static_cast<uint16_t>(DEFAULT_WALK_SPEED.count()); // cd->speed; - WFIFOW(s, 2 + 52) = unwrap<Species>(cd->species); - WFIFOW(s, 2 + 54) = cd->hair; - - WFIFOW(s, 2 + 58) = cd->base_level; - WFIFOW(s, 2 + 60) = cd->skill_point; - - WFIFOW(s, 2 + 64) = unwrap<ItemNameId>(cd->shield); - WFIFOW(s, 2 + 66) = unwrap<ItemNameId>(cd->head_top); - WFIFOW(s, 2 + 68) = unwrap<ItemNameId>(cd->head_mid); - WFIFOW(s, 2 + 70) = cd->hair_color; - - WFIFO_STRING(s, 2 + 74, ck->name.to__actual(), 24); - - WFIFOB(s, 2 + 98) = saturate<uint8_t>(cd->attrs[ATTR::STR]); - WFIFOB(s, 2 + 99) = saturate<uint8_t>(cd->attrs[ATTR::AGI]); - WFIFOB(s, 2 + 100) = saturate<uint8_t>(cd->attrs[ATTR::VIT]); - WFIFOB(s, 2 + 101) = saturate<uint8_t>(cd->attrs[ATTR::INT]); - WFIFOB(s, 2 + 102) = saturate<uint8_t>(cd->attrs[ATTR::DEX]); - WFIFOB(s, 2 + 103) = saturate<uint8_t>(cd->attrs[ATTR::LUK]); - WFIFOB(s, 2 + 104) = ck->char_num; - - WFIFOSET(s, 108); - } - RFIFOSKIP(s, 37); + Packet_Fixed<0x006d> fixed_6d; + + fixed_6d.char_select.char_id = ck->char_id; + fixed_6d.char_select.base_exp = cd->base_exp; + fixed_6d.char_select.zeny = cd->zeny; + fixed_6d.char_select.job_exp = cd->job_exp; + fixed_6d.char_select.job_level = cd->job_level; + + fixed_6d.char_select.shoes = ItemNameId(); + fixed_6d.char_select.gloves = ItemNameId(); + fixed_6d.char_select.cape = ItemNameId(); + fixed_6d.char_select.misc1 = ItemNameId(); + fixed_6d.char_select.option = Option(); + fixed_6d.char_select.unused = 0; + + // this was buggy until the protocol became generated + // but the client ignores it anyway + fixed_6d.char_select.karma = cd->karma; + fixed_6d.char_select.manner = cd->manner; + + fixed_6d.char_select.status_point = 0x30; + fixed_6d.char_select.hp = saturate<int16_t>(cd->hp); + fixed_6d.char_select.max_hp = saturate<int16_t>(cd->max_hp); + fixed_6d.char_select.sp = saturate<int16_t>(cd->sp); + fixed_6d.char_select.max_sp = saturate<int16_t>(cd->max_sp); + fixed_6d.char_select.speed = static_cast<uint16_t>(DEFAULT_WALK_SPEED.count()); // cd->speed; + fixed_6d.char_select.species = cd->species; + fixed_6d.char_select.hair_style = cd->hair; + fixed_6d.char_select.weapon = 0; + + fixed_6d.char_select.base_level = cd->base_level; + fixed_6d.char_select.skill_point = cd->skill_point; + + fixed_6d.char_select.head_bottom = ItemNameId(); + fixed_6d.char_select.shield = cd->shield; + fixed_6d.char_select.head_top = cd->head_top; + fixed_6d.char_select.head_mid = cd->head_mid; + fixed_6d.char_select.hair_color = cd->hair_color; + fixed_6d.char_select.misc2 = ItemNameId(); + + fixed_6d.char_select.char_name = ck->name; + + fixed_6d.char_select.stats.str = saturate<uint8_t>(cd->attrs[ATTR::STR]); + fixed_6d.char_select.stats.agi = saturate<uint8_t>(cd->attrs[ATTR::AGI]); + fixed_6d.char_select.stats.vit = saturate<uint8_t>(cd->attrs[ATTR::VIT]); + fixed_6d.char_select.stats.int_ = saturate<uint8_t>(cd->attrs[ATTR::INT]); + fixed_6d.char_select.stats.dex = saturate<uint8_t>(cd->attrs[ATTR::DEX]); + fixed_6d.char_select.stats.luk = saturate<uint8_t>(cd->attrs[ATTR::LUK]); + fixed_6d.char_select.char_num = ck->char_num; + fixed_6d.char_select.unused2 = 0; + + send_fpacket<0x006d, 108>(s, fixed_6d); break; + } case 0x68: // delete char //Yor's Fix - if (!sd || RFIFOREST(s) < 46) - return; { - AccountEmail email = stringish<AccountEmail>(RFIFO_STRING<40>(s, 6)); + Packet_Fixed<0x0068> fixed; + rv = recv_fpacket<0x0068, 46>(s, fixed); + if (rv != RecvResult::Complete) + break; + + if (!sd) + { + s->set_eof(); + return; + } + AccountEmail email = fixed.email; if (!e_mail_check(email)) email = DEFAULT_EMAIL; { { - CharId cid = wrap<CharId>(RFIFOL(s, 2)); + CharId cid = fixed.char_id; CharPair *cs = nullptr; for (CharPair& cd : char_keys) { @@ -2435,93 +2673,100 @@ void parse_char(Session *s) } char_keys.pop_back(); - WFIFOW(s, 0) = 0x6f; - WFIFOSET(s, 2); + Packet_Fixed<0x006f> fixed_6f; + send_fpacket<0x006f, 2>(s, fixed_6f); goto x68_out; } } { - WFIFOW(s, 0) = 0x70; - WFIFOB(s, 2) = 0; - WFIFOSET(s, 3); + Packet_Fixed<0x0070> fixed_70; + fixed_70.code = 0; + send_fpacket<0x0070, 3>(s, fixed_70); } } - } x68_out: - RFIFOSKIP(s, 46); break; + } case 0x2af8: // マップサーバーログイン - if (RFIFOREST(s) < 60) - return; { + Packet_Fixed<0x2af8> fixed; + rv = recv_fpacket<0x2af8, 60>(s, fixed); + if (rv != RecvResult::Complete) + break; + int i; - WFIFOW(s, 0) = 0x2af9; + Packet_Fixed<0x2af9> fixed_f9; for (i = 0; i < MAX_MAP_SERVERS; i++) { if (!server_session[i]) break; } - AccountName userid_ = stringish<AccountName>(RFIFO_STRING<24>(s, 2)); - AccountPass passwd_ = stringish<AccountPass>(RFIFO_STRING<24>(s, 26)); + AccountName userid_ = fixed.account_name; + AccountPass passwd_ = fixed.account_pass; if (i == MAX_MAP_SERVERS || userid_ != userid || passwd_ != passwd) { - WFIFOB(s, 2) = 3; - WFIFOSET(s, 3); - RFIFOSKIP(s, 60); + fixed_f9.code = 3; + send_fpacket<0x2af9, 3>(s, fixed_f9); } else { - int len; - WFIFOB(s, 2) = 0; + fixed_f9.code = 0; s->set_parsers(SessionParsers{.func_parse= parse_frommap, .func_delete= delete_frommap}); server_session[i] = s; if (anti_freeze_enable) server_freezeflag[i] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed - // ignore RFIFOL(fd, 50) - server[i].ip = RFIFOIP(s, 54); - server[i].port = RFIFOW(s, 58); + // ignore fixed.unknown + server[i].ip = fixed.ip; + server[i].port = fixed.port; server[i].users = 0; for (MapName& mapi : server[i].maps) mapi = MapName(); - WFIFOSET(s, 3); - RFIFOSKIP(s, 60); + send_fpacket<0x2af9, 3>(s, fixed_f9); realloc_fifo(s, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); // send gm acccounts level to map-servers - len = 4; - WFIFOW(s, 0) = 0x2b15; + std::vector<Packet_Repeat<0x2b15>> repeat_15(gm_accounts.size()); + auto it = repeat_15.begin(); for (const GM_Account& gma : gm_accounts) { - WFIFOL(s, len) = unwrap<AccountId>(gma.account_id); - WFIFOB(s, len + 4) = gma.level.get_all_bits(); - len += 5; + it->account_id = gma.account_id; + it->gm_level = gma.level; + ++it; } - WFIFOW(s, 2) = len; - WFIFOSET(s, len); + send_packet_repeatonly<0x2b15, 4, 5>(s, repeat_15); + // justification: we switched the session parsers + parse_frommap(s); return; } - } - break; - - case 0x187: // Alive信号? - if (RFIFOREST(s) < 6) - return; - RFIFOSKIP(s, 6); break; + } case 0x7530: // Athena情報所得 - WFIFOW(s, 0) = 0x7531; - WFIFO_STRUCT(s, 2, CURRENT_CHAR_SERVER_VERSION); - WFIFOSET(s, 10); - RFIFOSKIP(s, 2); - return; + { + Packet_Fixed<0x7530> fixed; + rv = recv_fpacket<0x7530, 2>(s, fixed); + if (rv != RecvResult::Complete) + break; + + Packet_Fixed<0x7531> fixed_31; + fixed_31.version = CURRENT_CHAR_SERVER_VERSION; + send_fpacket<0x7531, 10>(s, fixed_31); + break; + } case 0x7532: // 接続の切断(defaultと処理は一緒だが明示的にするため) + { + Packet_Fixed<0x7532> fixed; + rv = recv_fpacket<0x7532, 2>(s, fixed); + if (rv != RecvResult::Complete) + break; + s->set_eof(); return; + } default: s->set_eof(); @@ -2530,81 +2775,25 @@ void parse_char(Session *s) } } -// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendall(const uint8_t *buf, unsigned int len) -{ - int i, c; - - c = 0; - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - Session *s = server_session[i]; - if (s) - { - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); - c++; - } - } - return c; -} - -// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendallwos(Session *ss, const uint8_t *buf, unsigned int len) -{ - int i, c; - - c = 0; - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - Session *s = server_session[i]; - if (s && s != ss) - { - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); - c++; - } - } - return c; -} - -// MAPサーバーにデータ送信(map鯖生存確認有り) -int mapif_send(Session *s, const uint8_t *buf, unsigned int len) -{ - int i; - - if (s) - { - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - if (s == server_session[i]) - { - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); - return 1; - } - } - } - return 0; -} - static void send_users_tologin(TimerData *, tick_t) { int users = count_users(); - uint8_t buf[16]; if (login_session) { // send number of user to login server - WFIFOW(login_session, 0) = 0x2714; - WFIFOL(login_session, 2) = users; - WFIFOSET(login_session, 6); + Packet_Fixed<0x2714> fixed_14; + fixed_14.users = users; + send_fpacket<0x2714, 6>(login_session, fixed_14); } // send number of players to all map-servers - WBUFW(buf, 0) = 0x2b00; - WBUFL(buf, 2) = users; - mapif_sendall(buf, 6); + Packet_Fixed<0x2b00> fixed_00; + fixed_00.users = users; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x2b00, 6>(ss, fixed_00); + } } static @@ -2618,18 +2807,18 @@ void check_connect_login_server(TimerData *, tick_t) if (!login_session) return; realloc_fifo(login_session, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - WFIFOW(login_session, 0) = 0x2710; - WFIFO_ZERO(login_session, 2, 24); - WFIFO_STRING(login_session, 2, userid, 24); - WFIFO_STRING(login_session, 26, passwd, 24); - WFIFOL(login_session, 50) = 0; - WFIFOIP(login_session, 54) = char_ip; - WFIFOL(login_session, 58) = char_port; - WFIFO_STRING(login_session, 60, server_name, 20); - WFIFOW(login_session, 80) = 0; - WFIFOW(login_session, 82) = 0; //char_maintenance; - WFIFOW(login_session, 84) = 0; //char_new; - WFIFOSET(login_session, 86); + + Packet_Fixed<0x2710> fixed_10; + fixed_10.account_name = userid; + fixed_10.account_pass = passwd; + fixed_10.unknown = 0; + fixed_10.ip = char_ip; + fixed_10.port = char_port; + fixed_10.server_name = server_name; + fixed_10.unknown2 = 0; + fixed_10.maintenance = 0; + fixed_10.is_new = 0; + send_fpacket<0x2710, 86>(login_session, fixed_10); } } diff --git a/src/char/char.hpp b/src/char/char.hpp index 3ba455f..f8adeb9 100644 --- a/src/char/char.hpp +++ b/src/char/char.hpp @@ -45,9 +45,7 @@ const CharPair *search_character(CharName character_name); const CharPair *search_character_id(CharId char_id); Session *server_for(const CharPair *mcs); -int mapif_sendall(const uint8_t *buf, unsigned int len); -int mapif_sendallwos(Session *s, const uint8_t *buf, unsigned int len); -int mapif_send(Session *s, const uint8_t *buf, unsigned int len); +auto iter_map_sessions() -> decltype(filter_iterator<Session *>(std::declval<Array<Session *, MAX_MAP_SERVERS> *>())); void char_log(XString line); diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp index 056e11d..64e3158 100644 --- a/src/char/int_party.cpp +++ b/src/char/int_party.cpp @@ -33,7 +33,9 @@ #include "../io/read.hpp" #include "../io/write.hpp" -#include "../net/vomit.hpp" +#include "../net/packets.hpp" + +#include "../proto2/char-map.hpp" #include "../mmo/extract.hpp" #include "../mmo/ids.hpp" @@ -47,27 +49,27 @@ AString party_txt = "save/party.txt"_s; static -Map<PartyId, struct party> party_db; +Map<PartyId, PartyMost> party_db; static PartyId party_newid = wrap<PartyId>(100_u32); static void mapif_party_broken(PartyId party_id, int flag); static -int party_check_empty(struct party *p); +int party_check_empty(PartyPair p); static void mapif_parse_PartyLeave(Session *s, PartyId party_id, AccountId account_id); // パーティデータの文字列への変換 static -AString inter_party_tostr(struct party *p) +AString inter_party_tostr(PartyPair p) { MString str; str += STRPRINTF( "%d\t" "%s\t" "%d,%d\t"_fmt, - p->party_id, + p.party_id, p->name, p->exp, p->item); for (int i = 0; i < MAX_PARTY; i++) @@ -86,9 +88,9 @@ AString inter_party_tostr(struct party *p) } static -bool extract(XString str, party *p) +bool extract(XString str, PartyPair *pp) { - *p = party(); + PartyPair& p = *pp; // not compatible with the normal extract()ors since it has // a variable-size element that uses the same separator @@ -97,7 +99,7 @@ bool extract(XString str, party *p) return false; auto begin = bits.begin(); auto end = bits.end(); - if (begin == end || !extract(*begin, &p->party_id)) + if (begin == end || !extract(*begin, &p.party_id)) return false; ++begin; if (begin == end || !extract(*begin, &p->name)) @@ -125,7 +127,7 @@ bool extract(XString str, party *p) } static -void party_check_deleted_init(struct party *p) +void party_check_deleted_init(PartyPair p) { for (int i = 0; i < MAX_PARTY; i++) { @@ -136,10 +138,10 @@ void party_check_deleted_init(struct party *p) { CHAR_LOG("WARNING: deleting obsolete party member %d %s of %d %s\n"_fmt, p->member[i].account_id, p->member[i].name, - p->party_id, p->name); + p.party_id, p->name); PRINTF("WARNING: deleting obsolete party member %d %s of %d %s\n"_fmt, p->member[i].account_id, p->member[i].name, - p->party_id, p->name); + p.party_id, p->name); p->member[i] = party_member{}; } } @@ -165,14 +167,16 @@ void inter_party_init(void) continue; } - struct party p {}; - if (extract(line, &p) && p.party_id) + PartyMost pm; + PartyPair pp; + pp.party_most = ± + if (extract(line, &pp) && pp.party_id) { - if (party_newid < next(p.party_id)) - party_newid = next(p.party_id); - party_check_deleted_init(&p); - party_db.insert(p.party_id, p); - party_check_empty(&p); + if (party_newid < next(pp.party_id)) + party_newid = next(pp.party_id); + party_check_deleted_init(pp); + party_db.insert(pp.party_id, pm); + party_check_empty(pp); } else { @@ -185,7 +189,7 @@ void inter_party_init(void) // パーティーデータのセーブ用 static -void inter_party_save_sub(struct party *data, io::WriteFile& fp) +void inter_party_save_sub(PartyPair data, io::WriteFile& fp) { AString line = inter_party_tostr(data); fp.put_line(line); @@ -202,14 +206,19 @@ int inter_party_save(void) return 1; } for (auto& pair : party_db) - inter_party_save_sub(&pair.second, fp); + { + PartyPair tmp; + tmp.party_id = pair.first; + tmp.party_most = &pair.second; + inter_party_save_sub(tmp, fp); + } return 0; } // パーティ名検索用 static -void search_partyname_sub(struct party *p, PartyName str, struct party **dst) +void search_partyname_sub(PartyPair p, PartyName str, PartyPair *dst) { if (p->name == str) *dst = p; @@ -217,18 +226,23 @@ void search_partyname_sub(struct party *p, PartyName str, struct party **dst) // パーティ名検索 static -struct party *search_partyname(PartyName str) +PartyPair search_partyname(PartyName str) { - struct party *p = NULL; + PartyPair p; for (auto& pair : party_db) - search_partyname_sub(&pair.second, str, &p); + { + PartyPair tmp; + tmp.party_id = pair.first; + tmp.party_most = &pair.second; + search_partyname_sub(tmp, str, &p); + } return p; } // EXP公平分配できるかチェック static -int party_check_exp_share(struct party *p) +int party_check_exp_share(PartyPair p) { int i; int maxlv = 0, minlv = 0x7fffffff; @@ -249,7 +263,7 @@ int party_check_exp_share(struct party *p) } // パーティが空かどうかチェック -int party_check_empty(struct party *p) +int party_check_empty(PartyPair p) { int i; @@ -261,20 +275,20 @@ int party_check_empty(struct party *p) } } // 誰もいないので解散 - mapif_party_broken(p->party_id, 0); - party_db.erase(p->party_id); + mapif_party_broken(p.party_id, 0); + party_db.erase(p.party_id); return 1; } // キャラの競合がないかチェック用 static -void party_check_conflict_sub(struct party *p, +void party_check_conflict_sub(PartyPair p, PartyId party_id, AccountId account_id, CharName nick) { int i; - if (p->party_id == party_id) // 本来の所属なので問題なし + if (p.party_id == party_id) // 本来の所属なので問題なし return; for (i = 0; i < MAX_PARTY; i++) @@ -284,8 +298,8 @@ void party_check_conflict_sub(struct party *p, { // 別のパーティに偽の所属データがあるので脱退 PRINTF("int_party: party conflict! %d %d %d\n"_fmt, account_id, - party_id, p->party_id); - mapif_parse_PartyLeave(nullptr, p->party_id, account_id); + party_id, p.party_id); + mapif_parse_PartyLeave(nullptr, p.party_id, account_id); } } } @@ -295,8 +309,13 @@ static void party_check_conflict(PartyId party_id, AccountId account_id, CharName nick) { for (auto& pair : party_db) - party_check_conflict_sub(&pair.second, + { + PartyPair tmp; + tmp.party_id = pair.first; + tmp.party_most = &pair.second; + party_check_conflict_sub(tmp, party_id, account_id, nick); + } } //------------------------------------------------------------------- @@ -304,81 +323,92 @@ void party_check_conflict(PartyId party_id, AccountId account_id, CharName nick) // パーティ作成可否 static -void mapif_party_created(Session *s, AccountId account_id, struct party *p) +void mapif_party_created(Session *s, AccountId account_id, PartyPair p) { - WFIFOW(s, 0) = 0x3820; - WFIFOL(s, 2) = unwrap<AccountId>(account_id); - if (p != NULL) + Packet_Fixed<0x3820> fixed_20; + fixed_20.account_id = account_id; + if (p) { - WFIFOB(s, 6) = 0; - WFIFOL(s, 7) = unwrap<PartyId>(p->party_id); - WFIFO_STRING(s, 11, p->name, 24); - PRINTF("int_party: created! %d %s\n"_fmt, p->party_id, p->name); + fixed_20.error = 0; + fixed_20.party_id = p.party_id; + fixed_20.party_name = p->name; + PRINTF("int_party: created! %d %s\n"_fmt, p.party_id, p->name); } else { - WFIFOB(s, 6) = 1; - WFIFOL(s, 7) = 0; - WFIFO_STRING(s, 11, "error"_s, 24); + fixed_20.error = 1; + fixed_20.party_id = PartyId(); + fixed_20.party_name = stringish<PartyName>("error"_s); } - WFIFOSET(s, 35); + send_fpacket<0x3820, 35>(s, fixed_20); } // パーティ情報見つからず static void mapif_party_noinfo(Session *s, PartyId party_id) { - WFIFOW(s, 0) = 0x3821; - WFIFOW(s, 2) = 8; - WFIFOL(s, 4) = unwrap<PartyId>(party_id); - WFIFOSET(s, 8); + Packet_Head<0x3821> head_21; + Packet_Option<0x3821> option_21; + head_21.party_id = party_id; + send_opacket<0x3821, 8, sizeof(NetPacket_Option<0x3821>)>(s, head_21, false, option_21); PRINTF("int_party: info not found %d\n"_fmt, party_id); } // パーティ情報まとめ送り static -void mapif_party_info(Session *s, struct party *p) +void mapif_party_info(Session *s, PartyPair p) { - unsigned char buf[4 + sizeof(struct party)]; - - WBUFW(buf, 0) = 0x3821; - WBUF_STRUCT(buf, 4, *p); - WBUFW(buf, 2) = 4 + sizeof(struct party); + Packet_Head<0x3821> head_21; + head_21.party_id = p.party_id; + Packet_Option<0x3821> option_21; + option_21.party_most = *p.party_most; if (!s) - mapif_sendall(buf, WBUFW(buf, 2)); + { + for (Session *ss : iter_map_sessions()) + { + send_opacket<0x3821, 8, sizeof(NetPacket_Option<0x3821>)>(ss, head_21, true, option_21); + } + } else - mapif_send(s, buf, WBUFW(buf, 2)); + { + send_opacket<0x3821, 8, sizeof(NetPacket_Option<0x3821>)>(s, head_21, true, option_21); + } } // パーティメンバ追加可否 static void mapif_party_memberadded(Session *s, PartyId party_id, AccountId account_id, int flag) { - WFIFOW(s, 0) = 0x3822; - WFIFOL(s, 2) = unwrap<PartyId>(party_id); - WFIFOL(s, 6) = unwrap<AccountId>(account_id); - WFIFOB(s, 10) = flag; - WFIFOSET(s, 11); + Packet_Fixed<0x3822> fixed_22; + fixed_22.party_id = party_id; + fixed_22.account_id = account_id; + fixed_22.flag = flag; + send_fpacket<0x3822, 11>(s, fixed_22); } // パーティ設定変更通知 static -void mapif_party_optionchanged(Session *s, struct party *p, AccountId account_id, +void mapif_party_optionchanged(Session *s, PartyPair p, AccountId account_id, int flag) { - unsigned char buf[15]; - - WBUFW(buf, 0) = 0x3823; - WBUFL(buf, 2) = unwrap<PartyId>(p->party_id); - WBUFL(buf, 6) = unwrap<AccountId>(account_id); - WBUFW(buf, 10) = p->exp; - WBUFW(buf, 12) = p->item; - WBUFB(buf, 14) = flag; + Packet_Fixed<0x3823> fixed_23; + fixed_23.party_id = p.party_id; + fixed_23.account_id = account_id; + fixed_23.exp = p->exp; + fixed_23.item = p->item; + fixed_23.flag = flag; if (flag == 0) - mapif_sendall(buf, 15); + { + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x3823, 15>(ss, fixed_23); + } + } else - mapif_send(s, buf, 15); - PRINTF("int_party: option changed %d %d %d %d %d\n"_fmt, p->party_id, + { + send_fpacket<0x3823, 15>(s, fixed_23); + } + PRINTF("int_party: option changed %d %d %d %d %d\n"_fmt, p.party_id, account_id, p->exp, p->item, flag); } @@ -386,40 +416,47 @@ void mapif_party_optionchanged(Session *s, struct party *p, AccountId account_id static void mapif_party_leaved(PartyId party_id, AccountId account_id, CharName name) { - unsigned char buf[34]; + Packet_Fixed<0x3824> fixed_24; + fixed_24.party_id = party_id; + fixed_24.account_id = account_id; + fixed_24.char_name = name; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x3824, 34>(ss, fixed_24); + } - WBUFW(buf, 0) = 0x3824; - WBUFL(buf, 2) = unwrap<PartyId>(party_id); - WBUFL(buf, 6) = unwrap<AccountId>(account_id); - WBUF_STRING(buf, 10, name.to__actual(), 24); - mapif_sendall(buf, 34); PRINTF("int_party: party leaved %d %d %s\n"_fmt, party_id, account_id, name); } // パーティマップ更新通知 static -void mapif_party_membermoved(struct party *p, int idx) +void mapif_party_membermoved(PartyPair p, int idx) { assert (idx < MAX_PARTY); - unsigned char buf[29]; - WBUFW(buf, 0) = 0x3825; - WBUFL(buf, 2) = unwrap<PartyId>(p->party_id); - WBUFL(buf, 6) = unwrap<AccountId>(p->member[idx].account_id); - WBUF_STRING(buf, 10, p->member[idx].map, 16); - WBUFB(buf, 26) = p->member[idx].online; - WBUFW(buf, 27) = p->member[idx].lv; - mapif_sendall(buf, 29); + Packet_Fixed<0x3825> fixed_25; + fixed_25.party_id = p.party_id; + fixed_25.account_id = p->member[idx].account_id; + fixed_25.map_name = p->member[idx].map; + fixed_25.online = p->member[idx].online; + fixed_25.level = p->member[idx].lv; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x3825, 29>(ss, fixed_25); + } } // パーティ解散通知 void mapif_party_broken(PartyId party_id, int flag) { - unsigned char buf[7]; - WBUFW(buf, 0) = 0x3826; - WBUFL(buf, 2) = unwrap<PartyId>(party_id); - WBUFB(buf, 6) = flag; - mapif_sendall(buf, 7); + Packet_Fixed<0x3826> fixed_26; + fixed_26.party_id = party_id; + fixed_26.flag = flag; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x3826, 7>(ss, fixed_26); + } + PRINTF("int_party: broken %d\n"_fmt, party_id); CHAR_LOG("int_party: broken %d\n"_fmt, party_id); } @@ -428,15 +465,14 @@ void mapif_party_broken(PartyId party_id, int flag) static void mapif_party_message(PartyId party_id, AccountId account_id, XString mes) { - size_t len = mes.size() + 1; - unsigned char buf[len + 12]; - - WBUFW(buf, 0) = 0x3827; - WBUFW(buf, 2) = len + 12; - WBUFL(buf, 4) = unwrap<PartyId>(party_id); - WBUFL(buf, 8) = unwrap<AccountId>(account_id); - WBUF_STRING(buf, 12, mes, len); - mapif_sendall(buf, len + 12); + Packet_Head<0x3827> head_27; + XString repeat_27 = mes; + head_27.party_id = party_id; + head_27.account_id = account_id; + for (Session *ss : iter_map_sessions()) + { + send_vpacket<0x3827, 12, 1>(ss, head_27, repeat_27); + } } //------------------------------------------------------------------- @@ -451,20 +487,22 @@ void mapif_parse_CreateParty(Session *s, AccountId account_id, PartyName name, C if (!name.is_print()) { PRINTF("int_party: illegal party name [%s]\n"_fmt, name); - mapif_party_created(s, account_id, NULL); + mapif_party_created(s, account_id, PartyPair()); return; } } - if (search_partyname(name) != NULL) + if (search_partyname(name)) { PRINTF("int_party: same name party exists [%s]\n"_fmt, name); - mapif_party_created(s, account_id, NULL); + mapif_party_created(s, account_id, PartyPair()); return; } - struct party p {}; + PartyMost p {}; + PartyPair pp; + pp.party_most = &p; party_newid = next(party_newid); - p.party_id = party_newid; + pp.party_id = party_newid; p.name = name; p.exp = 0; p.item = 0; @@ -475,18 +513,19 @@ void mapif_parse_CreateParty(Session *s, AccountId account_id, PartyName name, C p.member[0].online = 1; p.member[0].lv = lv; - party_db.insert(p.party_id, p); + party_db.insert(pp.party_id, p); - mapif_party_created(s, account_id, &p); - mapif_party_info(s, &p); + mapif_party_created(s, account_id, pp); + mapif_party_info(s, pp); } // パーティ情報要求 static void mapif_parse_PartyInfo(Session *s, PartyId party_id) { - struct party *p = party_db.search(party_id); - if (p != NULL) + PartyPair p; + p.party_most = party_db.search(party_id); + if (p) mapif_party_info(s, p); else mapif_party_noinfo(s, party_id); @@ -497,8 +536,9 @@ static void mapif_parse_PartyAddMember(Session *s, PartyId party_id, AccountId account_id, CharName nick, MapName map, int lv) { - struct party *p = party_db.search(party_id); - if (p == NULL) + PartyPair p; + p.party_most = party_db.search(party_id); + if (!p) { mapif_party_memberadded(s, party_id, account_id, 1); return; @@ -537,8 +577,9 @@ static void mapif_parse_PartyChangeOption(Session *s, PartyId party_id, AccountId account_id, int exp, int item) { - struct party *p = party_db.search(party_id); - if (p == NULL) + PartyPair p; + p.party_most = party_db.search(party_id); + if (!p) return; p->exp = exp; @@ -557,7 +598,8 @@ void mapif_parse_PartyChangeOption(Session *s, PartyId party_id, AccountId accou // パーティ脱退要求 void mapif_parse_PartyLeave(Session *, PartyId party_id, AccountId account_id) { - struct party *p = party_db.search(party_id); + PartyPair p; + p.party_most = party_db.search(party_id); if (!p) return; for (int i = 0; i < MAX_PARTY; i++) @@ -578,8 +620,9 @@ static void mapif_parse_PartyChangeMap(Session *s, PartyId party_id, AccountId account_id, MapName map, int online, int lv) { - struct party *p = party_db.search(party_id); - if (p == NULL) + PartyPair p; + p.party_most = party_db.search(party_id); + if (!p) return; for (int i = 0; i < MAX_PARTY; i++) @@ -608,8 +651,9 @@ void mapif_parse_PartyChangeMap(Session *s, PartyId party_id, AccountId account_ static void mapif_parse_BreakParty(Session *, PartyId party_id) { - struct party *p = party_db.search(party_id); - if (p == NULL) + PartyPair p; + p.party_most = party_db.search(party_id); + if (!p) return; party_db.erase(party_id); @@ -635,117 +679,163 @@ void mapif_parse_PartyCheck(Session *, PartyId party_id, AccountId account_id, C // ・パケット長データはinter.cにセットしておくこと // ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない // ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_party_parse_frommap(Session *ms) +RecvResult inter_party_parse_frommap(Session *ms, uint16_t packet_id) { - switch (RFIFOW(ms, 0)) + RecvResult rv = RecvResult::Error; + switch (packet_id) { case 0x3020: { - AccountId account = wrap<AccountId>(RFIFOL(ms, 2)); - PartyName name = stringish<PartyName>(RFIFO_STRING<24>(ms, 6)); - CharName nick = stringish<CharName>(RFIFO_STRING<24>(ms, 30)); - MapName map = RFIFO_STRING<16>(ms, 54); - uint16_t lv = RFIFOW(ms, 70); + Packet_Fixed<0x3020> fixed; + rv = recv_fpacket<0x3020, 72>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + AccountId account = fixed.account_id; + PartyName name = fixed.party_name; + CharName nick = fixed.char_name; + MapName map = fixed.map_name; + uint16_t lv = fixed.level; mapif_parse_CreateParty(ms, account, name, nick, map, lv); - } break; + } case 0x3021: { - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 2)); + Packet_Fixed<0x3021> fixed; + rv = recv_fpacket<0x3021, 6>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; mapif_parse_PartyInfo(ms, party_id); - } break; + } case 0x3022: { - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 2)); - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 6)); - CharName nick = stringish<CharName>(RFIFO_STRING<24>(ms, 10)); - MapName map = RFIFO_STRING<16>(ms, 34); - uint16_t lv = RFIFOW(ms, 50); + Packet_Fixed<0x3022> fixed; + rv = recv_fpacket<0x3022, 52>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; + CharName nick = fixed.char_name; + MapName map = fixed.map_name; + uint16_t lv = fixed.level; mapif_parse_PartyAddMember(ms, party_id, account_id, nick, map, lv); - } break; + } case 0x3023: { - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 2)); - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 6)); - uint16_t exp = RFIFOW(ms, 10); - uint16_t item = RFIFOW(ms, 12); + Packet_Fixed<0x3023> fixed; + rv = recv_fpacket<0x3023, 14>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; + uint16_t exp = fixed.exp; + uint16_t item = fixed.item; mapif_parse_PartyChangeOption(ms, party_id, account_id, exp, item); - } break; + } case 0x3024: { - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 2)); - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 6)); + Packet_Fixed<0x3024> fixed; + rv = recv_fpacket<0x3024, 10>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; mapif_parse_PartyLeave(ms, party_id, account_id); - } break; + } case 0x3025: { - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 2)); - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 6)); - MapName map = RFIFO_STRING<16>(ms, 10); - uint8_t online = RFIFOB(ms, 26); - uint16_t lv = RFIFOW(ms, 27); + Packet_Fixed<0x3025> fixed; + rv = recv_fpacket<0x3025, 29>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; + MapName map = fixed.map_name; + uint8_t online = fixed.online; + uint16_t lv = fixed.level; mapif_parse_PartyChangeMap(ms, party_id, account_id, map, online, lv); - } break; + } case 0x3026: { - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 2)); + Packet_Fixed<0x3026> fixed; + rv = recv_fpacket<0x3026, 6>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; mapif_parse_BreakParty(ms, party_id); - } break; + } case 0x3027: { - size_t len = RFIFOW(ms, 2) - 12; - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 4)); - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 8)); - AString mes = RFIFO_STRING(ms, 12, len); + Packet_Head<0x3027> head; + AString repeat; + rv = recv_vpacket<0x3027, 12, 1>(ms, head, repeat); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = head.party_id; + AccountId account_id = head.account_id; + AString& mes = repeat; mapif_parse_PartyMessage(ms, party_id, account_id, mes); - } break; + } case 0x3028: { - PartyId party_id = wrap<PartyId>(RFIFOL(ms, 2)); - AccountId account_id = wrap<AccountId>(RFIFOL(ms, 6)); - CharName nick = stringish<CharName>(RFIFO_STRING<24>(ms, 10)); + Packet_Fixed<0x3028> fixed; + rv = recv_fpacket<0x3028, 34>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; + CharName nick = fixed.char_name; mapif_parse_PartyCheck(ms, party_id, account_id, nick); - } break; + } default: - return 0; + return RecvResult::Error; } - return 1; + return rv; } // サーバーから脱退要求(キャラ削除用) diff --git a/src/char/int_party.hpp b/src/char/int_party.hpp index ab42501..1d8cadc 100644 --- a/src/char/int_party.hpp +++ b/src/char/int_party.hpp @@ -32,7 +32,7 @@ void inter_party_init(void); int inter_party_save(void); -int inter_party_parse_frommap(Session *ms); +RecvResult inter_party_parse_frommap(Session *ms, uint16_t); void inter_party_leave(PartyId party_id, AccountId account_id); diff --git a/src/char/int_storage.cpp b/src/char/int_storage.cpp index 5cbc2a1..6ff6e2e 100644 --- a/src/char/int_storage.cpp +++ b/src/char/int_storage.cpp @@ -32,7 +32,9 @@ #include "../io/read.hpp" #include "../io/write.hpp" -#include "../net/vomit.hpp" +#include "../net/packets.hpp" + +#include "../proto2/char-map.hpp" #include "../mmo/extract.hpp" #include "../mmo/mmo.hpp" @@ -44,11 +46,11 @@ AString storage_txt = "save/storage.txt"_s; static -Map<AccountId, struct storage> storage_db; +Map<AccountId, Storage> storage_db; // 倉庫データを文字列に変換 static -AString storage_tostr(struct storage *p) +AString storage_tostr(Storage *p) { MString str; str += STRPRINTF( @@ -85,7 +87,7 @@ AString storage_tostr(struct storage *p) // 文字列を倉庫データに変換 static -bool extract(XString str, struct storage *p) +bool extract(XString str, Storage *p) { std::vector<struct item> storage_items; if (!extract(str, @@ -109,9 +111,9 @@ bool extract(XString str, struct storage *p) } // アカウントから倉庫データインデックスを得る(新規倉庫追加可能) -struct storage *account2storage(AccountId account_id) +Storage *account2storage(AccountId account_id) { - struct storage *s = storage_db.search(account_id); + Storage *s = storage_db.search(account_id); if (s == NULL) { s = storage_db.init(account_id); @@ -136,7 +138,7 @@ void inter_storage_init(void) AString line; while (in.getline(line)) { - struct storage s {}; + Storage s {}; if (extract(line, &s)) { storage_db.insert(s.account_id, s); @@ -151,7 +153,7 @@ void inter_storage_init(void) } static -void inter_storage_save_sub(struct storage *data, io::WriteFile& fp) +void inter_storage_save_sub(Storage *data, io::WriteFile& fp) { AString line = storage_tostr(data); if (line) @@ -188,53 +190,60 @@ void inter_storage_delete(AccountId account_id) static void mapif_load_storage(Session *ss, AccountId account_id) { - struct storage *st = account2storage(account_id); - WFIFOW(ss, 0) = 0x3810; - WFIFOW(ss, 2) = sizeof(struct storage) + 8; - WFIFOL(ss, 4) = unwrap<AccountId>(account_id); - WFIFO_STRUCT(ss, 8, *st); - WFIFOSET(ss, WFIFOW(ss, 2)); + Storage *st = account2storage(account_id); + Packet_Payload<0x3810> payload_10; + payload_10.account_id = account_id; + payload_10.storage = *st; + send_ppacket<0x3810>(ss, payload_10); } // 倉庫データ保存完了送信 static void mapif_save_storage_ack(Session *ss, AccountId account_id) { - WFIFOW(ss, 0) = 0x3811; - WFIFOL(ss, 2) = unwrap<AccountId>(account_id); - WFIFOB(ss, 6) = 0; - WFIFOSET(ss, 7); + Packet_Fixed<0x3811> fixed_11; + fixed_11.account_id = account_id; + fixed_11.unknown = 0; + send_fpacket<0x3811, 7>(ss, fixed_11); } //--------------------------------------------------------- // map serverからの通信 // 倉庫データ要求受信 -static -void mapif_parse_LoadStorage(Session *ss) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_LoadStorage(Session *ss) { - AccountId account_id = wrap<AccountId>(RFIFOL(ss, 2)); + Packet_Fixed<0x3010> fixed; + RecvResult rv = recv_fpacket<0x3010, 6>(ss, fixed); + if (rv != RecvResult::Complete) + return rv; + + AccountId account_id = fixed.account_id; mapif_load_storage(ss, account_id); + + return rv; } // 倉庫データ受信&保存 -static -void mapif_parse_SaveStorage(Session *ss) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_SaveStorage(Session *ss) { - struct storage *st; - AccountId account_id = wrap<AccountId>(RFIFOL(ss, 4)); - int len = RFIFOW(ss, 2); - if (sizeof(struct storage) != len - 8) - { - PRINTF("inter storage: data size error %zu %d\n"_fmt, - sizeof(struct storage), len - 8); - } - else + Packet_Payload<0x3011> payload; + RecvResult rv = recv_ppacket<0x3011>(ss, payload); + if (rv != RecvResult::Complete) + return rv; + + Storage *st; + AccountId account_id = payload.account_id; + { st = account2storage(account_id); - RFIFO_STRUCT(ss, 8, *st); + *st = payload.storage; mapif_save_storage_ack(ss, account_id); } + + return rv; } // map server からの通信 @@ -242,18 +251,19 @@ void mapif_parse_SaveStorage(Session *ss) // ・パケット長データはinter.cにセットしておくこと // ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない // ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_storage_parse_frommap(Session *ms) +RecvResult inter_storage_parse_frommap(Session *ms, uint16_t packet_id) { - switch (RFIFOW(ms, 0)) + RecvResult rv; + switch (packet_id) { case 0x3010: - mapif_parse_LoadStorage(ms); + rv = mapif_parse_LoadStorage(ms); break; case 0x3011: - mapif_parse_SaveStorage(ms); + rv = mapif_parse_SaveStorage(ms); break; default: - return 0; + return RecvResult::Error; } - return 1; + return rv; } diff --git a/src/char/int_storage.hpp b/src/char/int_storage.hpp index 83981b6..6bf3e1f 100644 --- a/src/char/int_storage.hpp +++ b/src/char/int_storage.hpp @@ -32,9 +32,9 @@ void inter_storage_init(void); int inter_storage_save(void); void inter_storage_delete(AccountId account_id); -struct storage *account2storage(AccountId account_id); +Storage *account2storage(AccountId account_id); -int inter_storage_parse_frommap(Session *ms); +RecvResult inter_storage_parse_frommap(Session *ms, uint16_t); extern AString storage_txt; diff --git a/src/char/inter.cpp b/src/char/inter.cpp index a4af7e5..9eb43cf 100644 --- a/src/char/inter.cpp +++ b/src/char/inter.cpp @@ -38,7 +38,9 @@ #include "../io/read.hpp" #include "../io/write.hpp" -#include "../net/vomit.hpp" +#include "../net/packets.hpp" + +#include "../proto2/char-map.hpp" #include "../mmo/extract.hpp" #include "../mmo/mmo.hpp" @@ -54,29 +56,15 @@ AString accreg_txt = "save/accreg.txt"_s; struct accreg { - int account_id, reg_num; + AccountId account_id; + int reg_num; Array<struct global_reg, ACCOUNT_REG_NUM> reg; }; static -Map<int, struct accreg> accreg_db; +Map<AccountId, struct accreg> accreg_db; int party_share_level = 10; -// 受信パケット長リスト -static -int inter_recv_packet_length[] = -{ - -1, -1, 7, -1, -1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 6, -1, 0, 0, 0, 0, 0, 0, 10, -1, 0, 0, 0, 0, 0, 0, - 72, 6, 52, 14, 10, 29, 6, -1, 34, 0, 0, 0, 0, 0, 0, 0, - -1, 6, -1, 0, 55, 19, 6, -1, 14, -1, -1, -1, 14, 19, 186, -1, - 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 48, 14, -1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - //-------------------------------------------------------- // アカウント変数を文字列へ変換 @@ -101,7 +89,7 @@ bool extract(XString str, struct accreg *reg) ®->account_id, vrec<' '>(&vars)))) return false; - if (reg->account_id <= 0) + if (!reg->account_id) return false; if (vars.size() > ACCOUNT_REG_NUM) @@ -218,14 +206,10 @@ void inter_init2() static void mapif_GMmessage(XString mes) { - size_t str_len = mes.size() + 1; - size_t msg_len = str_len + 4; - uint8_t buf[msg_len]; - - WBUFW(buf, 0) = 0x3800; - WBUFW(buf, 2) = msg_len; - WBUF_STRING(buf, 4, mes, str_len); - mapif_sendall(buf, msg_len); + for (Session *ss : iter_map_sessions()) + { + send_packet_repeatonly<0x3800, 4, 1>(ss, mes); + } } // Wisp/page transmission to correct map-server @@ -235,103 +219,105 @@ void mapif_wis_message(Session *tms, CharName src, CharName dst, XString msg) const CharPair *mcs = search_character(src); assert (mcs); - size_t str_size = msg.size() + 1; - uint8_t buf[56 + str_size]; - - WBUFW(buf, 0) = 0x3801; - WBUFW(buf, 2) = 56 + str_size; - WBUFL(buf, 4) = unwrap<CharId>(mcs->key.char_id); // formerly, whisper ID - WBUF_STRING(buf, 8, src.to__actual(), 24); - WBUF_STRING(buf, 32, dst.to__actual(), 24); - WBUF_STRING(buf, 56, msg, str_size); - mapif_send(tms, buf, WBUFW(buf, 2)); + Packet_Head<0x3801> head_01; + head_01.whisper_id = mcs->key.char_id; + head_01.src_char_name = src; + head_01.dst_char_name = dst; + send_vpacket<0x3801, 56, 1>(tms, head_01, msg); } // Wisp/page transmission result to map-server static void mapif_wis_end(Session *sms, CharName sender, int flag) { - uint8_t buf[27]; - - WBUFW(buf, 0) = 0x3802; - WBUF_STRING(buf, 2, sender.to__actual(), 24); - WBUFB(buf, 26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(sms, buf, 27); + Packet_Fixed<0x3802> fixed_02; + fixed_02.sender_char_name = sender; + fixed_02.flag = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + send_fpacket<0x3802, 27>(sms, fixed_02); } // アカウント変数送信 static -void mapif_account_reg(Session *s) +void mapif_account_reg(Session *s, AccountId account_id, const std::vector<Packet_Repeat<0x3004>>& repeat) { - size_t len = RFIFOW(s, 2); - uint8_t buf[len]; - RFIFO_BUF_CLONE(s, buf, len); - WBUFW(buf, 0) = 0x3804; - mapif_sendallwos(s, buf, WBUFW(buf, 2)); + Packet_Head<0x3804> head_04; + head_04.account_id = account_id; + std::vector<Packet_Repeat<0x3804>> repeat_04(repeat.size()); + for (size_t i = 0; i < repeat.size(); ++i) + { + repeat_04[i].name = repeat[i].name; + repeat_04[i].value = repeat[i].value; + } + + for (Session *ss : iter_map_sessions()) + { + if (ss == s) + continue; + send_vpacket<0x3804, 8, 36>(ss, head_04, repeat_04); + } } // アカウント変数要求返信 static -void mapif_account_reg_reply(Session *s, int account_id) +void mapif_account_reg_reply(Session *s, AccountId account_id) { struct accreg *reg = accreg_db.search(account_id); - WFIFOW(s, 0) = 0x3804; - WFIFOL(s, 4) = account_id; - if (reg == NULL) - { - WFIFOW(s, 2) = 8; - } - else + Packet_Head<0x3804> head_04; + head_04.account_id = account_id; + std::vector<Packet_Repeat<0x3804>> repeat_04; + if (reg) { + repeat_04.resize(reg->reg_num); assert (reg->reg_num < ACCOUNT_REG_NUM); - int j, p; - for (j = 0, p = 8; j < reg->reg_num; j++, p += 36) + for (size_t j = 0; j < reg->reg_num; ++j) { - WFIFO_STRING(s, p, reg->reg[j].str, 32); - WFIFOL(s, p + 32) = reg->reg[j].value; + repeat_04[j].name = reg->reg[j].str; + repeat_04[j].value = reg->reg[j].value; } - WFIFOW(s, 2) = p; } - WFIFOSET(s, WFIFOW(s, 2)); + send_vpacket<0x3804, 8, 36>(s, head_04, repeat_04); } //-------------------------------------------------------- // received packets from map-server // GMメッセージ送信 -static -void mapif_parse_GMmessage(Session *s) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_GMmessage(Session *s) { - size_t msg_len = RFIFOW(s, 2); - size_t str_len = msg_len - 4; - AString buf = RFIFO_STRING(s, 4, str_len); + AString repeat; + RecvResult rv = recv_packet_repeatonly<0x3000, 4, 1>(s, repeat); + if (rv != RecvResult::Complete) + return rv; + AString& buf = repeat; mapif_GMmessage(buf); + + return rv; } // Wisp/page request to send -static -void mapif_parse_WisRequest(Session *sms) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_WisRequest(Session *sms) { - if (RFIFOW(sms, 2) - 52 <= 0) - { // normaly, impossible, but who knows... - PRINTF("inter: Wis message doesn't exist.\n"_fmt); - return; - } + Packet_Head<0x3001> head; + AString repeat; + RecvResult rv = recv_vpacket<0x3001, 52, 1>(sms, head, repeat); + if (rv != RecvResult::Complete) + return rv; - CharName from = stringish<CharName>(RFIFO_STRING<24>(sms, 4)); - CharName to = stringish<CharName>(RFIFO_STRING<24>(sms, 28)); + CharName from = head.from_char_name; + CharName to = head.to_char_name; // search if character exists before to ask all map-servers const CharPair *mcs = search_character(to); if (!mcs) { - uint8_t buf[27]; - WBUFW(buf, 0) = 0x3802; - WBUF_STRING(buf, 2, from.to__actual(), 24); - WBUFB(buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(sms, buf, 27); + Packet_Fixed<0x3802> fixed_02; + fixed_02.sender_char_name = from; + fixed_02.flag = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + send_fpacket<0x3802, 27>(sms, fixed_02); // Character exists. So, ask all map-servers } else @@ -341,17 +327,15 @@ void mapif_parse_WisRequest(Session *sms) // if source is destination, don't ask other servers. if (from == to) { - uint8_t buf[27]; - WBUFW(buf, 0) = 0x3802; - WBUF_STRING(buf, 2, from.to__actual(), 24); - WBUFB(buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(sms, buf, 27); + Packet_Fixed<0x3802> fixed_02; + fixed_02.sender_char_name = from; + fixed_02.flag = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + send_fpacket<0x3802, 27>(sms, fixed_02); } else { - size_t len = RFIFOW(sms, 2) - 52; Session *tms = server_for(mcs); // for to - AString msg = RFIFO_STRING(sms, 52, len); + AString& msg = repeat; if (tms) { mapif_wis_message(tms, from, to, msg); @@ -362,69 +346,99 @@ void mapif_parse_WisRequest(Session *sms) } } } + + return rv; } // Wisp/page transmission result -static -int mapif_parse_WisReply(Session *tms) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_WisReply(Session *tms) { - CharId id = wrap<CharId>(RFIFOL(tms, 2)); - uint8_t flag = RFIFOB(tms, 6); + Packet_Fixed<0x3002> fixed; + RecvResult rv = recv_fpacket<0x3002, 7>(tms, fixed); + if (rv != RecvResult::Complete) + return rv; + + CharId id = fixed.char_id; + uint8_t flag = fixed.flag; const CharPair *smcs = search_character_id(id); CharName from = smcs->key.name; Session *sms = server_for(smcs); + { mapif_wis_end(sms, from, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target } - return 0; + return rv; } // Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) -static -void mapif_parse_WisToGM(Session *s) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_WisToGM(Session *s) { - size_t len = RFIFOW(s, 2); - uint8_t buf[len]; - // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B + Packet_Head<0x3003> head; + AString repeat; + RecvResult rv = recv_vpacket<0x3003, 30, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; + + Packet_Head<0x3803> head_03; + head_03.char_name = head.char_name; + head_03.min_gm_level = head.min_gm_level; + for (Session *ss : iter_map_sessions()) + { + send_vpacket<0x3803, 30, 1>(ss, head_03, repeat); + } - RFIFO_BUF_CLONE(s, buf, len); - WBUFW(buf, 0) = 0x3803; - mapif_sendall(buf, len); + return rv; } // アカウント変数保存要求 -static -void mapif_parse_AccReg(Session *s) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_AccReg(Session *s) { - int j, p; - struct accreg *reg = accreg_db.search(RFIFOL(s, 4)); + Packet_Head<0x3004> head; + std::vector<Packet_Repeat<0x3004>> repeat; + RecvResult rv = recv_vpacket<0x3004, 8, 36>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; + + struct accreg *reg = accreg_db.search(head.account_id); if (reg == NULL) { - int account_id = RFIFOL(s, 4); + AccountId account_id = head.account_id; reg = accreg_db.init(account_id); reg->account_id = account_id; } - for (j = 0, p = 8; j < ACCOUNT_REG_NUM && p < RFIFOW(s, 2); - j++, p += 36) + size_t jlim = std::min(repeat.size(), ACCOUNT_REG_NUM); + for (size_t j = 0; j < jlim; ++j) { - reg->reg[j].str = stringish<VarName>(RFIFO_STRING<32>(s, p)); - reg->reg[j].value = RFIFOL(s, p + 32); + reg->reg[j].str = repeat[j].name; + reg->reg[j].value = repeat[j].value; } - reg->reg_num = j; + reg->reg_num = jlim; // 他のMAPサーバーに送信 - mapif_account_reg(s); + mapif_account_reg(s, head.account_id, repeat); + + return rv; } // アカウント変数送信要求 -static -void mapif_parse_AccRegRequest(Session *s) +static __attribute__((warn_unused_result)) +RecvResult mapif_parse_AccRegRequest(Session *s) { - mapif_account_reg_reply(s, RFIFOL(s, 2)); + Packet_Fixed<0x3005> fixed; + RecvResult rv = recv_fpacket<0x3005, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + mapif_account_reg_reply(s, fixed.account_id); + + return rv; } //-------------------------------------------------------- @@ -432,70 +446,41 @@ void mapif_parse_AccRegRequest(Session *s) // map server からの通信(1パケットのみ解析すること) // エラーなら0(false)、処理できたなら1、 // パケット長が足りなければ2をかえさなければならない -int inter_parse_frommap(Session *ms) +RecvResult inter_parse_frommap(Session *ms, uint16_t packet_id) { - int cmd = RFIFOW(ms, 0); - int len = 0; - - // inter鯖管轄かを調べる - if (cmd < 0x3000 - || cmd >= - 0x3000 + - (sizeof(inter_recv_packet_length) / - sizeof(inter_recv_packet_length[0]))) - return 0; - - // パケット長を調べる - if ((len = - inter_check_length(ms, - inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; + int cmd = packet_id; + + RecvResult rv; switch (cmd) { case 0x3000: - mapif_parse_GMmessage(ms); + rv = mapif_parse_GMmessage(ms); break; case 0x3001: - mapif_parse_WisRequest(ms); + rv = mapif_parse_WisRequest(ms); break; case 0x3002: - mapif_parse_WisReply(ms); + rv = mapif_parse_WisReply(ms); break; case 0x3003: - mapif_parse_WisToGM(ms); + rv = mapif_parse_WisToGM(ms); break; case 0x3004: - mapif_parse_AccReg(ms); + rv = mapif_parse_AccReg(ms); break; case 0x3005: - mapif_parse_AccRegRequest(ms); + rv = mapif_parse_AccRegRequest(ms); break; default: - if (inter_party_parse_frommap(ms)) - break; - if (inter_storage_parse_frommap(ms)) - break; - return 0; + rv = inter_party_parse_frommap(ms, packet_id); + if (rv != RecvResult::Error) + return rv; + rv = inter_storage_parse_frommap(ms, packet_id); + if (rv != RecvResult::Error) + return rv; + return RecvResult::Error; } - RFIFOSKIP(ms, len); - - return 1; -} - -// RFIFOのパケット長確認 -// 必要パケット長があればパケット長、まだ足りなければ0 -int inter_check_length(Session *s, int length) -{ - if (length == -1) - { // 可変パケット長 - if (RFIFOREST(s) < 4) // パケット長が未着 - return 0; - length = RFIFOW(s, 2); - } - - if (RFIFOREST(s) < length) // パケットが未着 - return 0; - return length; + return rv; } diff --git a/src/char/inter.hpp b/src/char/inter.hpp index bb3c9da..9269017 100644 --- a/src/char/inter.hpp +++ b/src/char/inter.hpp @@ -30,9 +30,7 @@ bool inter_config(XString key, ZString value); void inter_init2(); void inter_save(void); -int inter_parse_frommap(Session *ms); - -int inter_check_length(Session *ms, int length); +RecvResult inter_parse_frommap(Session *ms, uint16_t packet_id); extern int party_share_level; |