summaryrefslogtreecommitdiff
path: root/src/char/char.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/char/char.cpp')
-rw-r--r--src/char/char.cpp1457
1 files changed, 823 insertions, 634 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);
}
}