summaryrefslogtreecommitdiff
path: root/src/char
diff options
context:
space:
mode:
Diffstat (limited to 'src/char')
-rw-r--r--src/char/char.cpp2138
-rw-r--r--src/char/char.hpp28
-rw-r--r--src/char/fwd.hpp27
-rw-r--r--src/char/int_party.cpp530
-rw-r--r--src/char/int_party.hpp21
-rw-r--r--src/char/int_storage.cpp133
-rw-r--r--src/char/int_storage.hpp23
-rw-r--r--src/char/inter.cpp348
-rw-r--r--src/char/inter.hpp19
-rw-r--r--src/char/main.cpp8
10 files changed, 1802 insertions, 1473 deletions
diff --git a/src/char/char.cpp b/src/char/char.cpp
index f8e12c0..b9cf17b 100644
--- a/src/char/char.cpp
+++ b/src/char/char.cpp
@@ -22,8 +22,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-#include <arpa/inet.h>
-#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
@@ -33,32 +31,45 @@
#include <cassert>
#include <cstdlib>
-#include <cstring>
-#include <ctime>
+#include <algorithm>
+#include <array>
#include <bitset>
+#include <chrono>
#include <set>
-#include "../compat/alg.hpp"
+#include "../ints/cmp.hpp"
+#include "../ints/udl.hpp"
#include "../strings/mstring.hpp"
#include "../strings/astring.hpp"
#include "../strings/zstring.hpp"
#include "../strings/xstring.hpp"
-#include "../generic/db.hpp"
+#include "../generic/array.hpp"
#include "../io/cxxstdio.hpp"
#include "../io/lock.hpp"
#include "../io/read.hpp"
#include "../io/tty.hpp"
+#include "../io/write.hpp"
+
+#include "../net/packets.hpp"
+#include "../net/socket.hpp"
+#include "../net/timer.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"
#include "../mmo/extract.hpp"
#include "../mmo/human_time_diff.hpp"
-#include "../mmo/socket.hpp"
-#include "../mmo/timer.hpp"
+#include "../mmo/mmo.hpp"
+#include "../mmo/utils.hpp"
#include "../mmo/version.hpp"
#include "inter.hpp"
@@ -67,6 +78,9 @@
#include "../poison.hpp"
+
+namespace tmwa
+{
static
Array<struct mmo_map_server, MAX_MAP_SERVERS> server;
static
@@ -76,11 +90,11 @@ Array<int, MAX_MAP_SERVERS> server_freezeflag; // Map-server anti-freeze syst
static
int anti_freeze_enable = 0;
static
-std::chrono::seconds anti_freeze_interval = std::chrono::seconds(6);
+std::chrono::seconds anti_freeze_interval = 6_s;
constexpr
std::chrono::milliseconds DEFAULT_AUTOSAVE_INTERVAL =
- std::chrono::minutes(5);
+ 5_min;
static
Session *login_session, *char_session;
@@ -91,7 +105,7 @@ AccountPass passwd;
static
ServerName server_name;
static
-CharName wisp_server_name = stringish<CharName>("Server");
+CharName wisp_server_name = stringish<CharName>("Server"_s);
static
IP4Address login_ip;
static
@@ -103,9 +117,9 @@ int char_port = 6121;
static
AString char_txt;
static
-CharName unknown_char_name = stringish<CharName>("Unknown");
+CharName unknown_char_name = stringish<CharName>("Unknown"_s);
static
-AString char_log_filename = "log/char.log";
+AString char_log_filename = "log/char.log"_s;
//Added for lan support
static
IP4Address lan_map_ip = IP4_LOCALHOST;
@@ -115,10 +129,14 @@ static
int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
static
std::bitset<256> char_name_letters; // list of letters/symbols authorised (or not) in a character name. by [Yor]
+static constexpr
+GmLevel default_gm_level = GmLevel::from(0_u32);
+
struct char_session_data : SessionData
{
- int account_id, login_id1, login_id2;
+ AccountId account_id;
+ int login_id1, login_id2;
SEX sex;
unsigned short packet_tmw_version;
AccountEmail email;
@@ -132,8 +150,8 @@ void SessionDeleter::operator()(SessionData *sd)
struct AuthFifoEntry
{
- int account_id;
- int char_id;
+ AccountId account_id;
+ CharId char_id;
int login_id1, login_id2;
IP4Address ip;
int delflag;
@@ -150,7 +168,7 @@ static
int check_ip_flag = 1; // It's to check IP of a player between char-server and other servers (part of anti-hacking system)
static
-int char_id_count = 150000;
+CharId char_id_count = wrap<CharId>(150000);
static
std::vector<CharPair> char_keys;
static
@@ -160,22 +178,22 @@ std::chrono::milliseconds autosave_time = DEFAULT_AUTOSAVE_INTERVAL;
// Initial position (it's possible to set it in conf file)
static
-struct point start_point = { {"001-1.gat"}, 273, 354 };
+Point start_point = { {"001-1.gat"_s}, 273, 354 };
static
std::vector<GM_Account> gm_accounts;
// online players by [Yor]
static
-AString online_txt_filename = "online.txt";
+AString online_txt_filename = "online.txt"_s;
static
-AString online_html_filename = "online.html";
+AString online_html_filename = "online.html"_s;
static
int online_sorting_option = 0; // sorting option to display online players in online files
static
int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer
static
-int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it
+GmLevel online_gm_display_min_level = GmLevel::from(20_u32); // minimum GM level to display 'GM' when we want to display it
static
std::vector<Session *> online_chars; // same size of char_keys, and id value of current server (or -1)
@@ -185,6 +203,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);
@@ -192,7 +218,7 @@ static
void delete_tologin(Session *sess)
{
assert (sess == login_session);
- PRINTF("Char-server can't connect to login-server (connection #%d).\n",
+ PRINTF("Char-server can't connect to login-server (connection #%d).\n"_fmt,
sess);
login_session = nullptr;
}
@@ -207,7 +233,7 @@ void delete_frommap(Session *sess)
auto it = std::find(server_session.begin(), server_session.end(), sess);
assert (it != server_session.end());
int id = it - server_session.begin();
- PRINTF("Map-server %d (session #%d) has disconnected.\n", id,
+ PRINTF("Map-server %d (session #%d) has disconnected.\n"_fmt, id,
sess);
server[id] = mmo_map_server{};
server_session[id] = nullptr;
@@ -233,12 +259,12 @@ void char_log(XString line)
// and returns its level (or 0 if it isn't a GM account or if not found)
//----------------------------------------------------------------------
static
-int isGM(int account_id)
+GmLevel isGM(AccountId account_id)
{
for (GM_Account& gma : gm_accounts)
if (gma.account_id == account_id)
return gma.level;
- return 0;
+ return default_gm_level;
}
//----------------------------------------------
@@ -264,7 +290,7 @@ const CharPair *search_character(CharName character_name)
return nullptr;
}
-const CharPair *search_character_id(int char_id)
+const CharPair *search_character_id(CharId char_id)
{
for (const CharPair& cd : char_keys)
{
@@ -317,7 +343,7 @@ AString mmo_char_tostr(struct CharPair *cp)
"%d,%d,%d\t"
"%d,%d,%d,%d,%d\t"
"%s,%d,%d\t"
- "%s,%d,%d,%d\t",
+ "%s,%d,%d,%d\t"_fmt,
k->char_id,
k->account_id, k->char_num,
k->name,
@@ -336,11 +362,12 @@ AString mmo_char_tostr(struct CharPair *cp)
// memos were here (no longer supported)
str_p += '\t';
- for (int i = 0; i < MAX_INVENTORY; i++)
+ for (IOff0 i : IOff0::iter())
+ {
if (p->inventory[i].nameid)
{
- str_p += STRPRINTF("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ",
- p->inventory[i].id,
+ str_p += STRPRINTF("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d "_fmt,
+ 0 /*id*/,
p->inventory[i].nameid,
p->inventory[i].amount,
p->inventory[i].equip,
@@ -353,33 +380,40 @@ AString mmo_char_tostr(struct CharPair *cp)
0 /*card[3]*/,
0 /*broken*/);
}
+ }
str_p += '\t';
// cart was here (no longer supported)
str_p += '\t';
for (SkillID i : erange(SkillID(), MAX_SKILL))
+ {
if (p->skill[i].lv)
{
- str_p += STRPRINTF("%d,%d ",
+ str_p += STRPRINTF("%d,%d "_fmt,
i,
- p->skill[i].lv | (uint16_t(p->skill[i].flags) << 16));
+ p->skill[i].lv | (static_cast<uint16_t>(p->skill[i].flags) << 16));
}
+ }
str_p += '\t';
assert (p->global_reg_num < GLOBAL_REG_NUM);
for (int i = 0; i < p->global_reg_num; i++)
+ {
if (p->global_reg[i].str)
- str_p += STRPRINTF("%s,%d ",
+ {
+ str_p += STRPRINTF("%s,%d "_fmt,
p->global_reg[i].str,
p->global_reg[i].value);
+ }
+ }
str_p += '\t';
return AString(str_p);
}
static
-bool extract(XString str, struct point *p)
+bool extract(XString str, Point *p)
{
return extract(str, record<','>(&p->map_, &p->x, &p->y));
}
@@ -414,10 +448,11 @@ bool extract(XString str, CharPair *cp)
uint32_t unused_guild_id, unused_pet_id;
XString unused_memos;
- std::vector<struct item> inventory;
+ std::vector<Item> inventory;
XString unused_cart;
std::vector<struct skill_loader> skills;
- std::vector<struct global_reg> vars;
+ std::vector<GlobalReg> vars;
+ XString hair_style;
if (!extract(str,
record<'\t'>(
&k->char_id,
@@ -430,7 +465,7 @@ bool extract(XString str, CharPair *cp)
record<','>(&p->status_point, &p->skill_point),
record<','>(&p->option, &p->karma, &p->manner),
record<','>(&p->party_id, &unused_guild_id, &unused_pet_id),
- record<','>(&p->hair, &p->hair_color, &p->clothes_color),
+ record<','>(&hair_style, &p->hair_color, &p->clothes_color),
record<','>(&p->weapon, &p->shield, &p->head_top, &p->head_mid, &p->head_bottom),
&p->last_point,
// somebody was silly and stuck partner id as a field
@@ -444,11 +479,19 @@ bool extract(XString str, CharPair *cp)
vrec<' '>(&vars))))
return false;
+ // leftover corruption from Platinum
+ if (hair_style == "-1"_s)
+ {
+ p->hair = 0;
+ }
+ else if (!extract(hair_style, &p->hair))
+ return false;
+
if (wisp_server_name == k->name)
return false;
// TODO replace *every* lookup with a map lookup
- static std::set<int> seen_ids;
+ static std::set<CharId> seen_ids;
static std::set<CharName> seen_names;
// we don't have to worry about deleted characters,
// this is only called during startup
@@ -499,10 +542,10 @@ int mmo_char_init(void)
io::ReadFile in(char_txt);
if (!in.is_open())
{
- PRINTF("Characters file not found: %s.\n", char_txt);
- CHAR_LOG("Characters file not found: %s.\n", char_txt);
- CHAR_LOG("Id for the next created character: %d.\n",
- char_id_count);
+ PRINTF("Characters file not found: %s.\n"_fmt, char_txt);
+ CHAR_LOG("Characters file not found: %s.\n"_fmt, char_txt);
+ CHAR_LOG("Id for the next created character: %d.\n"_fmt,
+ char_id_count);
return 0;
}
@@ -516,8 +559,8 @@ int mmo_char_init(void)
continue;
{
- int i, j = 0;
- if (SSCANF(line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0)
+ CharId i;
+ if (extract(line, record<'\t'>(&i, "%newid%"_s)))
{
if (char_id_count < i)
char_id_count = i;
@@ -528,21 +571,21 @@ int mmo_char_init(void)
CharPair cd;
if (!extract(line, &cd))
{
- CHAR_LOG("Char skipped\n%s", line);
+ CHAR_LOG("Char skipped\n%s"_fmt, line);
continue;
}
- if (cd.key.char_id >= char_id_count)
- char_id_count = cd.key.char_id + 1;
+ if (char_id_count < next(cd.key.char_id))
+ char_id_count = next(cd.key.char_id);
char_keys.push_back(std::move(cd));
online_chars.push_back(nullptr);
}
- PRINTF("mmo_char_init: %zu characters read in %s.\n",
+ PRINTF("mmo_char_init: %zu characters read in %s.\n"_fmt,
char_keys.size(), char_txt);
- CHAR_LOG("mmo_char_init: %zu characters read in %s.\n",
+ CHAR_LOG("mmo_char_init: %zu characters read in %s.\n"_fmt,
char_keys.size(), char_txt);
- CHAR_LOG("Id for the next created character: %d.\n",
+ CHAR_LOG("Id for the next created character: %d.\n"_fmt,
char_id_count);
return 0;
@@ -557,8 +600,8 @@ void mmo_char_sync(void)
io::WriteLock fp(char_txt);
if (!fp.is_open())
{
- PRINTF("WARNING: Server can't not save characters.\n");
- CHAR_LOG("WARNING: Server can't not save characters.\n");
+ PRINTF("WARNING: Server can't not save characters.\n"_fmt);
+ CHAR_LOG("WARNING: Server can't not save characters.\n"_fmt);
return;
}
{
@@ -568,7 +611,7 @@ void mmo_char_sync(void)
AString line = mmo_char_tostr(&cd);
fp.put_line(line);
}
- FPRINTF(fp, "%d\t%%newid%%\n", char_id_count);
+ FPRINTF(fp, "%d\t%%newid%%\n"_fmt, char_id_count);
}
}
@@ -612,7 +655,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());
@@ -620,24 +663,24 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui
// remove control characters from the name
if (!name.to__actual().is_print())
{
- CHAR_LOG("Make new char error (control char received in the name): (connection #%d, account: %d).\n",
- s, sd->account_id);
+ CHAR_LOG("Make new char error (control char received in the name): (connection #%d, account: %d).\n"_fmt,
+ s, sd->account_id);
return nullptr;
}
// Eliminate whitespace
if (name.to__actual() != name.to__actual().strip())
{
- CHAR_LOG("Make new char error (leading/trailing whitespace): (connection #%d, account: %d, name: '%s'.\n",
- s, sd->account_id, name);
+ CHAR_LOG("Make new char error (leading/trailing whitespace): (connection #%d, account: %d, name: '%s'.\n"_fmt,
+ s, sd->account_id, name);
return nullptr;
}
// check lenght of character name
if (name.to__actual().size() < 4)
{
- CHAR_LOG("Make new char error (character name too small): (connection #%d, account: %d, name: '%s').\n",
- s, sd->account_id, name);
+ CHAR_LOG("Make new char error (character name too small): (connection #%d, account: %d, name: '%s').\n"_fmt,
+ s, sd->account_id, name);
return nullptr;
}
@@ -648,7 +691,7 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui
for (uint8_t c : name.to__actual())
if (!char_name_letters[c])
{
- CHAR_LOG("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n",
+ CHAR_LOG("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n"_fmt,
s, sd->account_id, name, c);
return nullptr;
}
@@ -659,36 +702,38 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui
for (uint8_t c : name.to__actual())
if (char_name_letters[c])
{
- CHAR_LOG("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n",
+ CHAR_LOG("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n"_fmt,
s, sd->account_id, name, c);
return nullptr;
}
} // 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",
- 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],
- hair_style, hair_color);
+ 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.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;
}
// 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",
- 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],
- hair_style, hair_color);
+ 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.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;
}
}
@@ -697,63 +742,63 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui
{
if (cd.key.name == name)
{
- 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",
- 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],
- hair_style, hair_color);
+ 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.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;
}
if (cd.key.account_id == sd->account_id
&& cd.key.char_num == slot)
{
- 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",
- 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],
- hair_style, hair_color);
+ 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.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;
}
}
if (wisp_server_name == name)
{
- 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",
- 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],
- hair_style, hair_color);
+ 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.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;
}
IP4Address ip = s->client_ip;
- 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",
- 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],
- hair_style, hair_color, ip);
+ 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.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;
CharKey& ck = cp.key;
CharData& cd = *cp.data;
- ck.char_id = char_id_count++;
+ ck.char_id = char_id_count; char_id_count = next(char_id_count);
ck.account_id = sd->account_id;
ck.char_num = slot;
ck.name = name;
- cd.species = 0;
+ cd.species = Species();
cd.base_level = 1;
cd.job_level = 1;
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;
@@ -763,17 +808,17 @@ CharPair *make_new_char(Session *s, CharName name, const uint8_t (&stats)[6], ui
cd.option = static_cast<Option>(0x0000); // Option is only declared
cd.karma = 0;
cd.manner = 0;
- cd.party_id = 0;
+ cd.party_id = PartyId();
//cd.guild_id = 0;
cd.hair = hair_style;
cd.hair_color = hair_color;
cd.clothes_color = 0;
// removed initial armor/weapon - unused and problematic
cd.weapon = ItemLook::NONE;
- cd.shield = 0;
- cd.head_top = 0;
- cd.head_mid = 0;
- cd.head_bottom = 0;
+ cd.shield = ItemNameId();
+ cd.head_top = ItemNameId();
+ cd.head_mid = ItemNameId();
+ cd.head_bottom = ItemNameId();
cd.last_point = start_point;
cd.save_point = start_point;
char_keys.push_back(std::move(cp));
@@ -799,17 +844,17 @@ void create_online_files(void)
timestamp_seconds_buffer timetemp;
stamp_time(timetemp);
// write heading
- FPRINTF(fp2, "<HTML>\n");
- FPRINTF(fp2, " <META http-equiv=\"Refresh\" content=\"%d\">\n", online_refresh_html); // update on client explorer every x seconds
- FPRINTF(fp2, " <HEAD>\n");
- FPRINTF(fp2, " <TITLE>Online Players on %s</TITLE>\n",
- server_name);
- FPRINTF(fp2, " </HEAD>\n");
- FPRINTF(fp2, " <BODY>\n");
- FPRINTF(fp2, " <H3>Online Players on %s (%s):</H3>\n",
- server_name, timetemp);
- FPRINTF(fp, "Online Players on %s (%s):\n", server_name, timetemp);
- FPRINTF(fp, "\n");
+ FPRINTF(fp2, "<HTML>\n"_fmt);
+ FPRINTF(fp2, " <META http-equiv=\"Refresh\" content=\"%d\">\n"_fmt, online_refresh_html); // update on client explorer every x seconds
+ FPRINTF(fp2, " <HEAD>\n"_fmt);
+ FPRINTF(fp2, " <TITLE>Online Players on %s</TITLE>\n"_fmt,
+ server_name);
+ FPRINTF(fp2, " </HEAD>\n"_fmt);
+ FPRINTF(fp2, " <BODY>\n"_fmt);
+ FPRINTF(fp2, " <H3>Online Players on %s (%s):</H3>\n"_fmt,
+ server_name, timetemp);
+ FPRINTF(fp, "Online Players on %s (%s):\n"_fmt, server_name, timetemp);
+ FPRINTF(fp, "\n"_fmt);
int players = 0;
// This used to be conditional on having any players,
@@ -817,20 +862,20 @@ void create_online_files(void)
//if (players > 0)
{
int j = 0; // count the number of characters for the txt version and to set the separate line
- FPRINTF(fp2, " <table border=\"1\" cellspacing=\"1\">\n");
- FPRINTF(fp2, " <tr>\n");
+ FPRINTF(fp2, " <table border=\"1\" cellspacing=\"1\">\n"_fmt);
+ FPRINTF(fp2, " <tr>\n"_fmt);
{
- FPRINTF(fp2, " <th>Name</th>\n");
+ FPRINTF(fp2, " <th>Name</th>\n"_fmt);
{
- FPRINTF(fp, "Name "); // 30
+ FPRINTF(fp, "Name "_fmt); // 30
j += 30;
}
}
- FPRINTF(fp2, " </tr>\n");
- FPRINTF(fp, "\n");
+ FPRINTF(fp2, " </tr>\n"_fmt);
+ FPRINTF(fp, "\n"_fmt);
for (int k = 0; k < j; k++)
- FPRINTF(fp, "-");
- FPRINTF(fp, "\n");
+ FPRINTF(fp, "-"_fmt);
+ FPRINTF(fp, "\n"_fmt);
// display each player.
for (CharPair& cd : char_keys)
@@ -838,55 +883,55 @@ void create_online_files(void)
if (!server_for(&cd))
continue;
players++;
- FPRINTF(fp2, " <tr>\n");
+ FPRINTF(fp2, " <tr>\n"_fmt);
// displaying the character name
{
// without/with 'GM' display
- int gml = isGM(cd.key.account_id);
+ GmLevel gml = isGM(cd.key.account_id);
{
- if (gml >= online_gm_display_min_level)
- FPRINTF(fp, "%-24s (GM) ", cd.key.name);
+ if (gml.satisfies(online_gm_display_min_level))
+ FPRINTF(fp, "%-24s (GM) "_fmt, cd.key.name);
else
- FPRINTF(fp, "%-24s ", cd.key.name);
+ FPRINTF(fp, "%-24s "_fmt, cd.key.name);
}
// name of the character in the html (no < >, because that create problem in html code)
- FPRINTF(fp2, " <td>");
- if (gml >= online_gm_display_min_level)
- FPRINTF(fp2, "<b>");
+ FPRINTF(fp2, " <td>"_fmt);
+ if (gml.satisfies(online_gm_display_min_level))
+ FPRINTF(fp2, "<b>"_fmt);
for (char c : cd.key.name.to__actual())
{
switch (c)
{
case '&':
- FPRINTF(fp2, "&amp;");
+ FPRINTF(fp2, "&amp;"_fmt);
break;
case '<':
- FPRINTF(fp2, "&lt;");
+ FPRINTF(fp2, "&lt;"_fmt);
break;
case '>':
- FPRINTF(fp2, "&gt;");
+ FPRINTF(fp2, "&gt;"_fmt);
break;
default:
- FPRINTF(fp2, "%c", c);
+ FPRINTF(fp2, "%c"_fmt, c);
break;
};
}
- if (gml >= online_gm_display_min_level)
- FPRINTF(fp2, "</b> (GM)");
- FPRINTF(fp2, "</td>\n");
+ if (gml.satisfies(online_gm_display_min_level))
+ FPRINTF(fp2, "</b> (GM)"_fmt);
+ FPRINTF(fp2, "</td>\n"_fmt);
}
- FPRINTF(fp, "\n");
- FPRINTF(fp2, " </tr>\n");
+ FPRINTF(fp, "\n"_fmt);
+ FPRINTF(fp2, " </tr>\n"_fmt);
}
- FPRINTF(fp2, " </table>\n");
- FPRINTF(fp, "\n");
+ FPRINTF(fp2, " </table>\n"_fmt);
+ FPRINTF(fp, "\n"_fmt);
}
// Displaying number of online players
if (players == 0)
{
- FPRINTF(fp2, " <p>No user is online.</p>\n");
- FPRINTF(fp, "No user is online.\n");
+ FPRINTF(fp2, " <p>No user is online.</p>\n"_fmt);
+ FPRINTF(fp, "No user is online.\n"_fmt);
}
else if (players == 1)
{
@@ -894,11 +939,11 @@ void create_online_files(void)
}
else
{
- FPRINTF(fp2, " <p>%d users are online.</p>\n", players);
- FPRINTF(fp, "%d users are online.\n", players);
+ FPRINTF(fp2, " <p>%d users are online.</p>\n"_fmt, players);
+ FPRINTF(fp, "%d users are online.\n"_fmt, players);
}
- FPRINTF(fp2, " </BODY>\n");
- FPRINTF(fp2, "</HTML>\n");
+ FPRINTF(fp2, " </BODY>\n"_fmt);
+ FPRINTF(fp2, "</HTML>\n"_fmt);
}
}
@@ -925,14 +970,18 @@ int count_users(void)
// [Fate] Find inventory item based on equipment mask, return view. ID must match view ID (!).
//----------------------------------------
static
-int find_equip_view(const CharPair *cp, EPOS equipmask)
+ItemNameId find_equip_view(const CharPair *cp, EPOS equipmask)
{
CharData *p = cp->data.get();
- for (int i = 0; i < MAX_INVENTORY; i++)
+ for (IOff0 i : IOff0::iter())
+ {
if (p->inventory[i].nameid && p->inventory[i].amount
&& bool(p->inventory[i].equip & equipmask))
+ {
return p->inventory[i].nameid;
- return 0;
+ }
+ }
+ return ItemNameId();
}
//----------------------------------------
@@ -954,72 +1003,75 @@ 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) = 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) = find_equip_view(cp, EPOS::SHOES);
- WFIFOW(s, j + 22) = find_equip_view(cp, EPOS::GLOVES);
- WFIFOW(s, j + 24) = find_equip_view(cp, EPOS::CAPE);
- WFIFOW(s, j + 26) = 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) = (p->hp > 0x7fff) ? 0x7fff : p->hp;
- WFIFOW(s, j + 44) = (p->max_hp > 0x7fff) ? 0x7fff : p->max_hp;
- WFIFOW(s, j + 46) = (p->sp > 0x7fff) ? 0x7fff : p->sp;
- WFIFOW(s, j + 48) = (p->max_sp > 0x7fff) ? 0x7fff : p->max_sp;
- WFIFOW(s, j + 50) = static_cast<uint16_t>(DEFAULT_WALK_SPEED.count()); // p->speed;
- WFIFOW(s, j + 52) = 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) = p->head_bottom;
- WFIFOW(s, j + 64) = p->shield;
- WFIFOW(s, j + 66) = p->head_top;
- WFIFOW(s, j + 68) = p->head_mid;
- WFIFOW(s, j + 70) = p->hair_color;
- WFIFOW(s, j + 72) = 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) = min(p->attrs[ATTR::STR], 255);
- WFIFOB(s, j + 99) = min(p->attrs[ATTR::AGI], 255);
- WFIFOB(s, j + 100) = min(p->attrs[ATTR::VIT], 255);
- WFIFOB(s, j + 101) = min(p->attrs[ATTR::INT], 255);
- WFIFOB(s, j + 102) = min(p->attrs[ATTR::DEX], 255);
- WFIFOB(s, j + 103) = min(p->attrs[ATTR::LUK], 255);
- 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;
}
static
-int set_account_reg2(int acc, Slice<global_reg> reg)
+int set_account_reg2(AccountId acc, Slice<GlobalReg> reg)
{
size_t num = reg.size();
assert (num < ACCOUNT_REG2_NUM);
@@ -1032,7 +1084,7 @@ int set_account_reg2(int acc, Slice<global_reg> reg)
cd.data->account_reg2[i] = reg[i];
cd.data->account_reg2_num = num;
for (int i = num; i < ACCOUNT_REG2_NUM; ++i)
- cd.data->account_reg2[i] = global_reg{};
+ cd.data->account_reg2[i] = GlobalReg{};
c++;
}
}
@@ -1043,52 +1095,65 @@ int set_account_reg2(int acc, Slice<global_reg> reg)
static
int char_divorce(CharPair *cp)
{
- uint8_t buf[10];
-
- if (cp == NULL)
+ if (cp == nullptr)
return 0;
CharKey *ck = &cp->key;
CharData *cs = cp->data.get();
- if (cs->partner_id <= 0)
+ if (!cs->partner_id)
{
- WBUFW(buf, 0) = 0x2b12;
- WBUFL(buf, 2) = ck->char_id;
- WBUFL(buf, 6) = 0; // partner id 0 means failure
- mapif_sendall(buf, 10);
+ Packet_Fixed<0x2b12> fixed_12;
+ fixed_12.char_id = ck->char_id;
+ // partner id 0 means failure
+ 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) = 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) = cs->partner_id;
- mapif_sendall(buf, 10);
- cs->partner_id = 0;
- cd.data->partner_id = 0;
+ 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;
}
// The other char doesn't have us as their partner, so just clear our partner
// 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) = cs->partner_id;
- mapif_sendall(buf, 10);
- cs->partner_id = 0;
+ 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) = cs->partner_id;
- cs->partner_id = 0;
- mapif_sendall(buf, 10);
+ fixed_12.partner_id = cs->partner_id;
+ cs->partner_id = CharId();
+ for (Session *ss : iter_map_sessions())
+ {
+ send_fpacket<0x2b12, 10>(ss, fixed_12);
+ }
return 0;
}
@@ -1097,25 +1162,24 @@ int char_divorce(CharPair *cp)
// Force disconnection of an online player (with account value) by [Yor]
//----------------------------------------------------------------------
static
-int disconnect_player(int accound_id)
+void disconnect_player(AccountId accound_id)
{
// disconnect player if online on char-server
for (io::FD i : iter_fds())
{
- if (!get_session(i))
+ Session *s = get_session(i);
+ if (!s)
continue;
- struct char_session_data *sd = static_cast<char_session_data *>(get_session(i)->session_data.get());
+ struct char_session_data *sd = static_cast<char_session_data *>(s->session_data.get());
if (sd)
{
if (sd->account_id == accound_id)
{
- get_session(i)->set_eof();
- return 1;
+ s->set_eof();
+ return;
}
}
}
-
- return 0;
}
// キャラ削除に伴うデータ削除
@@ -1134,10 +1198,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) = 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;
@@ -1146,143 +1212,156 @@ int char_delete(CharPair *cp)
static
void parse_tologin(Session *ls)
{
- // only login-server can have an access to here.
- // so, if it isn't the login-server, we disconnect the session (fd != login_fd).
- if (ls != login_session)
- {
- ls->set_eof();
- return;
- }
+ assert (ls == login_session);
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))
{
-// PRINTF("parse_tologin: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
-
- 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("connect login server error : %d\n", RFIFOB(fd,2));
- PRINTF("Can not connect to login-server.\n");
- PRINTF("The server communication passwords (default s1/p1) is probably invalid.\n");
- PRINTF("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n");
- PRINTF("If you changed the communication passwords, change them back at map_athena.conf and char_athena.conf\n");
+ PRINTF("Can not connect to login-server.\n"_fmt);
+ PRINTF("The server communication passwords (default s1/p1) is probably invalid.\n"_fmt);
+ PRINTF("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n"_fmt);
+ PRINTF("If you changed the communication passwords, change them back at map_athena.conf and char_athena.conf\n"_fmt);
exit(1);
}
else
{
- PRINTF("Connected to login-server (connection #%d).\n",
+ PRINTF("Connected to login-server (connection #%d).\n"_fmt,
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");
+ PRINTF("Awaiting maps from map-server.\n"_fmt);
}
- RFIFOSKIP(ls, 3);
break;
+ }
case 0x2713:
- if (RFIFOREST(ls) < 51)
- return;
-// PRINTF("parse_tologin 2713 : %d\n", RFIFOB(fd,6));
+ {
+ Packet_Fixed<0x2713> fixed;
+ rv = recv_fpacket<0x2713, 51>(ls, fixed);
+ if (rv != RecvResult::Complete)
+ break;
+
for (io::FD i : iter_fds())
{
+ 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 == RFIFOL(ls, 2))
+ 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)
{
-// if (max_connect_user == 0)
-// PRINTF("max_connect_user (unlimited) -> accepted.\n");
-// else
-// PRINTF("count_users(): %d < max_connect_user (%d) -> accepted.\n", 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
-// PRINTF("count_users(): %d < max_connect_use (%d) -> fail...\n", count_users(), max_connect_user);
- 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 = fixed.account_id;
Session *s2 = get_session(i);
if (!s2)
continue;
sd = static_cast<char_session_data *>(s2->session_data.get());
if (sd)
{
- if (sd->account_id == RFIFOL(ls, 2))
+ 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;
+
{
- unsigned char buf[10];
- WBUFW(buf, 0) = 0x2b0b;
- WBUFL(buf, 2) = RFIFOL(ls, 2); // account
- WBUFL(buf, 6) = RFIFOL(ls, 6); // GM level
- mapif_sendall(buf, 10);
-// PRINTF("parse_tologin: To become GM answer: char -> map.\n");
+ 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];
- int acc = RFIFOL(ls, 2);
- SEX sex = static_cast<SEX>(RFIFOB(ls, 6));
- RFIFOSKIP(ls, 7);
- if (acc > 0)
+ AccountId acc = fixed.account_id;
+ SEX sex = fixed.sex;
+ if (acc)
{
for (CharPair& cp : char_keys)
{
@@ -1293,35 +1372,43 @@ void parse_tologin(Session *ls)
cd.sex = sex;
// auth_fifo[i].sex = sex;
// to avoid any problem with equipment and invalid sex, equipment is unequiped.
- for (int j = 0; j < MAX_INVENTORY; j++)
+ for (IOff0 j : IOff0::iter())
{
if (cd.inventory[j].nameid
&& bool(cd.inventory[j].equip))
cd.inventory[j].equip = EPOS::ZERO;
}
cd.weapon = ItemLook::NONE;
- cd.shield = 0;
- cd.head_top = 0;
- cd.head_mid = 0;
- cd.head_bottom = 0;
+ cd.shield = ItemNameId();
+ cd.head_top = ItemNameId();
+ cd.head_mid = ItemNameId();
+ cd.head_bottom = ItemNameId();
}
}
// disconnect player if online on char-server
disconnect_player(acc);
}
- WBUFW(buf, 0) = 0x2b0d;
- WBUFL(buf, 2) = 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)
- CHAR_LOG("Receiving a message for broadcast, but message is void.\n");
+ {
+ 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
{
int i;
@@ -1330,82 +1417,100 @@ void parse_tologin(Session *ls)
if (server_session[i])
break;
if (i == MAX_MAP_SERVERS)
- CHAR_LOG("'ladmin': Receiving a message for broadcast, but no map-server is online.\n");
+ 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");
+ CHAR_LOG("Receiving a message for broadcast, but message is only a lot of spaces.\n"_fmt);
// else send message to all map-servers
else
{
- CHAR_LOG("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n",
+ 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, acc;
- acc = RFIFOL(ls, 4);
- for (p = 8, j = 0;
- p < RFIFOW(ls, 2) && j < ACCOUNT_REG2_NUM;
- p += 36, j++)
+ Array<GlobalReg, ACCOUNT_REG2_NUM> reg;
+ int j = 0;
+ AccountId acc = head.account_id;
+ for (const auto& info : repeat)
+ {
+ reg[j].str = info.name;
+ reg[j].value = info.value;
+ ++j;
+ if (j == ACCOUNT_REG2_NUM)
+ break;
+ }
+ set_account_reg2(acc, Slice<GlobalReg>(reg.begin(), j));
+
+ 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())
{
- reg[j].str = stringish<VarName>(RFIFO_STRING<32>(ls, p));
- reg[j].value = RFIFOL(ls, p + 32);
+ send_vpacket<0x2b11, 8, 36>(ss, head_11, repeat_11);
}
- 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);
-// PRINTF("char: save_account_reg_reply\n");
}
- RFIFOSKIP(ls, RFIFOW(ls, 2));
break;
+ }
case 0x7924:
{ // [Fate] Itemfrob package: forwarded from login-server
- if (RFIFOREST(ls) < 10)
- return;
- int source_id = RFIFOL(ls, 2);
- int dest_id = 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;
+
+ Packet_Fixed<0x2afa> fixed_fa;
+ fixed_fa.source_item_id = source_id;
+ fixed_fa.dest_item_id = dest_id;
- WBUFW(buf, 0) = 0x2afa;
- WBUFL(buf, 2) = source_id;
- WBUFL(buf, 6) = 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; }
- for (j = 0; j < MAX_INVENTORY; j++)
+ for (IOff0 j : IOff0::iter())
+ {
FIX(c->inventory[j].nameid);
+ }
// used to FIX cart, but it's no longer supported
// FIX(c->weapon);
FIX(c->shield);
@@ -1414,26 +1519,35 @@ void parse_tologin(Session *ls)
FIX(c->head_bottom);
if (s)
- for (j = 0; j < s->storage_amount; j++)
+ {
+ for (SOff0 j : SOff0::iter())
+ {
FIX(s->storage_[j].nameid);
+ }
+ }
#undef FIX
if (changes)
- CHAR_LOG("itemfrob(%d -> %d): `%s'(%d, account %d): changed %d times\n",
- source_id, dest_id, k->name, k->char_id,
- k->account_id, changes);
+ CHAR_LOG("itemfrob(%d -> %d): `%s'(%d, account %d): changed %d times\n"_fmt,
+ source_id, dest_id, k->name, k->char_id,
+ k->account_id, changes);
}
mmo_char_sync();
inter_storage_save();
- RFIFOSKIP(ls, 10);
break;
}
// Account deletion notification (from login-server)
case 0x2730:
- if (RFIFOREST(ls) < 6)
- return;
+ {
+ 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."
// needs to use index because they may move during resize
@@ -1441,7 +1555,7 @@ void parse_tologin(Session *ls)
{
CharPair& cp = char_keys[idx];
CharKey& ck = cp.key;
- if (ck.account_id == RFIFOL(ls, 2))
+ if (ck.account_id == aid)
{
char_delete(&cp);
if (&cp != &char_keys.back())
@@ -1450,7 +1564,7 @@ void parse_tologin(Session *ls)
// if moved character owns to deleted account, check again it's character
// YES this is the newly swapped one
// we could avoid this by working backwards
- if (ck.account_id == RFIFOL(ls, 2))
+ if (ck.account_id == aid)
{
idx--;
// Correct moved character reference in the character's owner by [Yor]
@@ -1460,69 +1574,91 @@ void parse_tologin(Session *ls)
}
}
// Deletion of the storage
- inter_storage_delete(RFIFOL(ls, 2));
+ inter_storage_delete(aid);
// send to all map-servers to disconnect the player
{
- unsigned char buf[6];
- WBUFW(buf, 0) = 0x2b13;
- WBUFL(buf, 2) = RFIFOL(ls, 2);
- 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(RFIFOL(ls, 2));
- RFIFOSKIP(ls, 6);
+ disconnect_player(aid);
break;
+ }
// State change of account/ban notification (from login-server) by [Yor]
case 0x2731:
- if (RFIFOREST(ls) < 11)
- return;
+ {
+ 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) = RFIFOL(ls, 2);
- 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(RFIFOL(ls, 2));
- RFIFOSKIP(ls, 11);
+ disconnect_player(aid);
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({static_cast<int>(RFIFOL(ls, i)), 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",
- gm_accounts.size());
- CHAR_LOG("From login-server: receiving of %zu GM accounts information.\n",
- gm_accounts.size());
+ PRINTF("From login-server: receiving of %zu GM accounts information.\n"_fmt,
+ gm_accounts.size());
+ CHAR_LOG("From login-server: receiving of %zu GM accounts information.\n"_fmt,
+ 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;
+
{
- int acc = RFIFOL(ls, 2);
- int status = RFIFOB(ls, 6);
+ AccountId acc = fixed.account_id;
+ int status = fixed.status;
for (io::FD i : iter_fds())
{
@@ -1534,22 +1670,26 @@ 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;
+ }
}
}
+ if (rv == RecvResult::Error)
+ ls->set_eof();
}
//--------------------------------
@@ -1560,18 +1700,16 @@ void map_anti_freeze_system(TimerData *, tick_t)
{
int i;
- //PRINTF("Entering in map_anti_freeze_system function to check freeze of servers.\n");
for (i = 0; i < MAX_MAP_SERVERS; i++)
{
if (server_session[i])
{ // if map-server is online
- //PRINTF("map_anti_freeze_system: server #%d, flag: %d.\n", i, server_freezeflag[i]);
if (server_freezeflag[i]-- < 1)
{ // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed
- PRINTF("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n",
- i);
- CHAR_LOG("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n",
- i);
+ PRINTF("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n"_fmt,
+ i);
+ CHAR_LOG("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n"_fmt,
+ i);
server_session[i]->set_eof();
}
}
@@ -1591,102 +1729,125 @@ 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))
{
-// PRINTF("parse_frommap: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
-
- 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",
- id, j, server[id].ip, server[id].port);
- PRINTF("Map-server %d loading complete.\n", id);
- CHAR_LOG("Map-Server %d connected: %d maps, from IP %s port %d. Map-server %d loading complete.\n",
- id, j, server[id].ip,
- server[id].port, id);
+ 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: %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", id);
- CHAR_LOG("WARNING: Map-Server %d have NO map.\n",
- id);
+ PRINTF("WARNING: Map-Server %d have NO map.\n"_fmt, id);
+ CHAR_LOG("WARNING: Map-Server %d have NO map.\n"_fmt,
+ id);
// Transmitting maps information to the other map-servers
}
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;
{
- int account_id = RFIFOL(ms, 2);
- int char_id = RFIFOL(ms, 6);
- int login_id1 = RFIFOL(ms, 10);
- int login_id2 = RFIFOL(ms, 14);
- IP4Address ip = RFIFOIP(ms, 18);
- //PRINTF("auth_fifo search: account: %d, char: %d, secure: %08x-%08x\n", RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14));
+ 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 &&
@@ -1706,46 +1867,49 @@ void parse_frommap(Session *ms)
break;
}
}
- assert (cp && "uh-oh - deleted while in queue?");
+ assert (cp && "uh-oh - deleted while in queue?"_s);
CharKey *ck = &cp->key;
CharData *cd = cp->data.get();
afi.delflag = 1;
- WFIFOW(ms, 0) = 0x2afd;
- WFIFOW(ms, 2) = 18 + sizeof(*ck) + sizeof(*cd);
- WFIFOL(ms, 4) = 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",
- (&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));
- //PRINTF("auth_fifo search success (auth #%d, account %d, character: %d).\n", i, RFIFOL(fd,2), RFIFOL(fd,6));
+ "From queue index %zd: recalling packet version %d\n"_fmt,
+ (&afi - &auth_fifo.front()), afi.packet_tmw_version);
+ 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) = account_id;
- WFIFOSET(ms, 6);
- PRINTF("auth_fifo search error! account %d not authentified.\n",
+ 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
@@ -1758,7 +1922,7 @@ void parse_frommap(Session *ms)
// add online players in the list by [Yor]
for (int i = 0; i < server[id].users; i++)
{
- int char_id = 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)
@@ -1776,306 +1940,374 @@ 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;
+ {
+ 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 == RFIFOL(ms, 4) &&
- cd.key.char_id == RFIFOL(ms, 8))
+ 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;
{
- int account_id = 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 = 0;
- auth_fifo_iter->login_id1 = RFIFOL(ms, 6);
- auth_fifo_iter->login_id2 = RFIFOL(ms, 10);
+ auth_fifo_iter->char_id = CharId();
+ 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) = 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 = RFIFOL(ms, 2);
- auth_fifo_iter->char_id = 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)
- if (cd.key.account_id == RFIFOL(ms, 2) &&
- cd.key.char_id == 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>(login_session, 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;
+
{
- int acc = 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) = 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 == -1
- || isGM(acc) >= isGM(ck->account_id))
+ {
+ 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) = 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 == -1
- || isGM(acc) >= isGM(ck->account_id))
+ {
+ 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) = 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 == -1
- || isGM(acc) >= isGM(ck->account_id))
+ {
+ 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) = 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 == -1
- || isGM(acc) >= isGM(ck->account_id))
+ {
+ 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) = 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 == -1
- || isGM(acc) >= isGM(ck->account_id))
+ {
+ 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) = 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 != -1)
+ 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;
- int acc = RFIFOL(ms, 4);
- for (p = 8, j = 0;
- p < RFIFOW(ms, 2) && j < ACCOUNT_REG2_NUM;
- p += 36, j++)
+ Array<GlobalReg, ACCOUNT_REG2_NUM> reg;
+ 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<GlobalReg>(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 = fixed.char_id;
for (CharPair& cd : char_keys)
- if (cd.key.char_id == RFIFOL(ms, 2))
+ {
+ 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",
- RFIFOW(ms, 0), RFIFOREST(ms));
+ PRINTF("char: unknown packet 0x%04x (%zu bytes to read in buffer)! (from map).\n"_fmt,
+ packet_id, packet_avail(ms));
ms->set_eof();
return;
+ }
}
}
+ if (rv == RecvResult::Error)
+ ms->set_eof();
}
static
@@ -2104,8 +2336,8 @@ int lan_ip_check(IP4Address addr)
{
bool lancheck = lan_subnet.covers(addr);
- PRINTF("LAN test (result): %s.\n",
- (lancheck) ? SGR_BOLD SGR_CYAN "LAN source" SGR_RESET : SGR_BOLD SGR_GREEN "WAN source" SGR_RESET);
+ PRINTF("LAN test (result): %s.\n"_fmt,
+ (lancheck) ? SGR_BOLD SGR_CYAN "LAN source" SGR_RESET ""_s : SGR_BOLD SGR_GREEN "WAN source" SGR_RESET ""_s);
return lancheck;
}
@@ -2127,9 +2359,9 @@ void handle_x0066(Session *s, struct char_session_data *sd, uint8_t rfifob_2, IP
CharKey *ck = &cp->key;
CharData *cd = cp->data.get();
- CHAR_LOG("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s [%s]\n",
- sd->account_id, rfifob_2,
- ck->name, ip);
+ CHAR_LOG("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s [%s]\n"_fmt,
+ sd->account_id, rfifob_2,
+ ck->name, ip);
// searching map server
int i = search_mapserver(cd->last_point.map_);
// if map is not found, we check major cities
@@ -2144,33 +2376,35 @@ void handle_x0066(Session *s, struct char_session_data *sd, uint8_t rfifob_2, IP
{ // change save point to one of map found on the server (the first)
i = j;
cd->last_point.map_ = server[j].maps[0];
- PRINTF("Map-server #%d found with a map: '%s'.\n",
- j, server[j].maps[0]);
+ PRINTF("Map-server #%d found with a map: '%s'.\n"_fmt,
+ j, server[j].maps[0]);
// coordonates are unknown
break;
}
// 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) = ck->char_id;
- WFIFO_STRING(s, 6, cd->last_point.map_, 16);
- PRINTF("Character selection '%s' (account: %d, slot: %d) [%s]\n",
- ck->name,
- sd->account_id, ck->char_num, ip);
- PRINTF("--Send IP of map-server. ");
+
+ 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;
@@ -2192,73 +2426,75 @@ void parse_char(Session *s)
{
IP4Address ip = s->client_ip;
+ assert (s != login_session);
+
if (!login_session)
{
s->set_eof();
-
- // I sure *hope* this doesn't happen ...
- if (s == login_session)
- login_session = nullptr;
return;
}
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))
{
-// if (RFIFOW(fd,0) < 30000)
-// PRINTF("parse_char: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
-
- 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) = 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;
+
{
- int account_id = RFIFOL(s, 2);
- int GM_value = isGM(account_id);
+ 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",
+ PRINTF("Account Logged On; Account ID: %d (GM level %d).\n"_fmt,
account_id, GM_value);
else
- PRINTF("Account Logged On; Account ID: %d.\n",
+ PRINTF("Account Logged On; Account ID: %d.\n"_fmt,
account_id);
- if (sd == NULL)
+ if (sd == nullptr)
{
s->session_data = make_unique<char_session_data, SessionDeleter>();
sd = static_cast<char_session_data *>(s->session_data.get());
- sd->email = stringish<AccountEmail>("no mail"); // put here a mail without '@' to refuse deletion if we don't receive the e-mail
+ sd->email = stringish<AccountEmail>("no mail"_s); // put here a mail without '@' to refuse deletion if we don't receive the e-mail
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));
- // send back account_id
- WFIFOL(s, 0) = account_id;
- WFIFOSET(s, 4);
+ sd->login_id1 = fixed.login_id1;
+ sd->login_id2 = fixed.login_id2;
+ sd->packet_tmw_version = fixed.packet_tmw_version;
+ sd->sex = fixed.sex;
+
+ // formerly: send back account_id
+ Packet_Payload<0x8000> special;
+ special.magic_packet_length = 4;
+ send_ppacket<0x8000>(s, special);
+
// search authentification
for (AuthFifoEntry& afi : auth_fifo)
{
@@ -2273,12 +2509,12 @@ void parse_char(Session *s)
if (max_connect_user == 0
|| count_users() < max_connect_user)
{
- if (login_session)
- { // don't send request if no login-server
+ {
+ // there is always a login server
// request to login-server to obtain e-mail/time limit
- WFIFOW(login_session, 0) = 0x2716;
- WFIFOL(login_session, 2) = 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 =
@@ -2289,126 +2525,153 @@ 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;
}
}
// authentification not found
{
- 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) = 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);
- }
- else
- { // if no login-server, we must refuse connection
- WFIFOW(s, 0) = 0x6c;
- WFIFOB(s, 2) = 0;
- WFIFOSET(s, 3);
+ // there is always a login-server
+ 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);
}
}
}
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) = 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) = min(cd->hp, 0x7fff);
- WFIFOW(s, 2 + 44) = min(cd->max_hp, 0x7fff);
- WFIFOW(s, 2 + 46) = min(cd->sp, 0x7fff);
- WFIFOW(s, 2 + 48) = min(cd->max_sp, 0x7fff);
- WFIFOW(s, 2 + 50) = static_cast<uint16_t>(DEFAULT_WALK_SPEED.count()); // cd->speed;
- WFIFOW(s, 2 + 52) = 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) = cd->shield;
- WFIFOW(s, 2 + 66) = cd->head_top;
- WFIFOW(s, 2 + 68) = cd->head_mid;
- WFIFOW(s, 2 + 70) = cd->hair_color;
-
- WFIFO_STRING(s, 2 + 74, ck->name.to__actual(), 24);
-
- WFIFOB(s, 2 + 98) = min(cd->attrs[ATTR::STR], 255);
- WFIFOB(s, 2 + 99) = min(cd->attrs[ATTR::AGI], 255);
- WFIFOB(s, 2 + 100) = min(cd->attrs[ATTR::VIT], 255);
- WFIFOB(s, 2 + 101) = min(cd->attrs[ATTR::INT], 255);
- WFIFOB(s, 2 + 102) = min(cd->attrs[ATTR::DEX], 255);
- WFIFOB(s, 2 + 103) = min(cd->attrs[ATTR::LUK], 255);
- 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 = fixed.char_id;
CharPair *cs = nullptr;
for (CharPair& cd : char_keys)
{
- if (cd.key.char_id == RFIFOL(s, 2))
+ if (cd.key.char_id == cid)
{
if (cd.key.account_id == sd->account_id)
cs = &cd;
@@ -2426,176 +2689,129 @@ 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;
- s->set_parsers(SessionParsers{func_parse: parse_frommap, func_delete: delete_frommap});
+ 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) = gma.account_id;
- WFIFOB(s, len + 4) = gma.level;
- 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();
return;
}
}
-}
-
-// 全ての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;
+ if (rv == RecvResult::Error)
+ s->set_eof();
}
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
@@ -2603,24 +2819,24 @@ void check_connect_login_server(TimerData *, tick_t)
{
if (!login_session)
{
- PRINTF("Attempt to connect to login-server...\n");
+ PRINTF("Attempt to connect to login-server...\n"_fmt);
login_session = make_connection(login_ip, login_port,
- SessionParsers{func_parse: parse_tologin, func_delete: delete_tologin});
+ SessionParsers{.func_parse= parse_tologin, .func_delete= delete_tologin});
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);
}
}
@@ -2630,14 +2846,14 @@ void check_connect_login_server(TimerData *, tick_t)
static
bool char_lan_config(XString w1, ZString w2)
{
- struct hostent *h = NULL;
+ struct hostent *h = nullptr;
{
- if (w1 == "lan_map_ip")
+ if (w1 == "lan_map_ip"_s)
{
// Read map-server Lan IP Address
h = gethostbyname(w2.c_str());
- if (h != NULL)
+ if (h != nullptr)
{
lan_map_ip = IP4Address({
static_cast<uint8_t>(h->h_addr[0]),
@@ -2648,20 +2864,20 @@ bool char_lan_config(XString w1, ZString w2)
}
else
{
- PRINTF("Bad IP value: %s\n", w2);
+ PRINTF("Bad IP value: %s\n"_fmt, w2);
return false;
}
- PRINTF("LAN IP of map-server: %s.\n", lan_map_ip);
+ PRINTF("LAN IP of map-server: %s.\n"_fmt, lan_map_ip);
}
- else if (w1 == "subnet" /*backward compatibility*/
- || w1 == "lan_subnet")
+ else if (w1 == "subnet"_s /*backward compatibility*/
+ || w1 == "lan_subnet"_s)
{
if (!extract(w2, &lan_subnet))
{
- PRINTF("Bad IP mask: %s\n", w2);
+ PRINTF("Bad IP mask: %s\n"_fmt, w2);
return false;
}
- PRINTF("Sub-network of the map-server: %s.\n",
+ PRINTF("Sub-network of the map-server: %s.\n"_fmt,
lan_subnet);
}
else
@@ -2677,10 +2893,10 @@ bool lan_check()
{
// sub-network check of the map-server
{
- PRINTF("LAN test of LAN IP of the map-server: ");
+ PRINTF("LAN test of LAN IP of the map-server: "_fmt);
if (!lan_ip_check(lan_map_ip))
{
- PRINTF(SGR_BOLD SGR_RED "***ERROR: LAN IP of the map-server doesn't belong to the specified Sub-network." SGR_RESET "\n");
+ PRINTF(SGR_BOLD SGR_RED "***ERROR: LAN IP of the map-server doesn't belong to the specified Sub-network." SGR_RESET "\n"_fmt);
return false;
}
}
@@ -2691,27 +2907,27 @@ bool lan_check()
static
bool char_config(XString w1, ZString w2)
{
- struct hostent *h = NULL;
+ struct hostent *h = nullptr;
{
- if (w1 == "userid")
+ if (w1 == "userid"_s)
userid = stringish<AccountName>(w2);
- else if (w1 == "passwd")
+ else if (w1 == "passwd"_s)
passwd = stringish<AccountPass>(w2);
- else if (w1 == "server_name")
+ else if (w1 == "server_name"_s)
{
server_name = stringish<ServerName>(w2);
- PRINTF("%s server has been intialized\n", w2);
+ PRINTF("%s server has been intialized\n"_fmt, w2);
}
- else if (w1 == "wisp_server_name")
+ else if (w1 == "wisp_server_name"_s)
{
if (w2.size() >= 4)
wisp_server_name = stringish<CharName>(w2);
}
- else if (w1 == "login_ip")
+ else if (w1 == "login_ip"_s)
{
h = gethostbyname(w2.c_str());
- if (h != NULL)
+ if (h != nullptr)
{
login_ip = IP4Address({
static_cast<uint8_t>(h->h_addr[0]),
@@ -2719,23 +2935,23 @@ bool char_config(XString w1, ZString w2)
static_cast<uint8_t>(h->h_addr[2]),
static_cast<uint8_t>(h->h_addr[3]),
});
- PRINTF("Login server IP address : %s -> %s\n",
+ PRINTF("Login server IP address : %s -> %s\n"_fmt,
w2, login_ip);
}
else
{
- PRINTF("Bad IP value: %s\n", w2);
+ PRINTF("Bad IP value: %s\n"_fmt, w2);
return false;
}
}
- else if (w1 == "login_port")
+ else if (w1 == "login_port"_s)
{
login_port = atoi(w2.c_str());
}
- else if (w1 == "char_ip")
+ else if (w1 == "char_ip"_s)
{
h = gethostbyname(w2.c_str());
- if (h != NULL)
+ if (h != nullptr)
{
char_ip = IP4Address({
static_cast<uint8_t>(h->h_addr[0]),
@@ -2743,56 +2959,56 @@ bool char_config(XString w1, ZString w2)
static_cast<uint8_t>(h->h_addr[2]),
static_cast<uint8_t>(h->h_addr[3]),
});
- PRINTF("Character server IP address : %s -> %s\n",
+ PRINTF("Character server IP address : %s -> %s\n"_fmt,
w2, char_ip);
}
else
{
- PRINTF("Bad IP value: %s\n", w2);
+ PRINTF("Bad IP value: %s\n"_fmt, w2);
return false;
}
}
- else if (w1 == "char_port")
+ else if (w1 == "char_port"_s)
{
char_port = atoi(w2.c_str());
}
- else if (w1 == "char_txt")
+ else if (w1 == "char_txt"_s)
{
char_txt = w2;
}
- else if (w1 == "max_connect_user")
+ else if (w1 == "max_connect_user"_s)
{
max_connect_user = atoi(w2.c_str());
if (max_connect_user < 0)
max_connect_user = 0; // unlimited online players
}
- else if (w1 == "check_ip_flag")
+ else if (w1 == "check_ip_flag"_s)
{
check_ip_flag = config_switch(w2);
}
- else if (w1 == "autosave_time")
+ else if (w1 == "autosave_time"_s)
{
autosave_time = std::chrono::seconds(atoi(w2.c_str()));
if (autosave_time <= std::chrono::seconds::zero())
autosave_time = DEFAULT_AUTOSAVE_INTERVAL;
}
- else if (w1 == "start_point")
+ else if (w1 == "start_point"_s)
{
extract(w2, &start_point);
}
- else if (w1 == "unknown_char_name")
+ else if (w1 == "unknown_char_name"_s)
{
unknown_char_name = stringish<CharName>(w2);
}
- else if (w1 == "char_log_filename")
+ else if (w1 == "char_log_filename"_s)
{
char_log_filename = w2;
}
- else if (w1 == "char_name_option")
+ else if (w1 == "char_name_option"_s)
{
char_name_option = atoi(w2.c_str());
}
- else if (w1 == "char_name_letters")
+ else if (w1 == "char_name_letters"_s)
{
if (!w2)
char_name_letters.reset();
@@ -2800,39 +3016,38 @@ bool char_config(XString w1, ZString w2)
for (uint8_t c : w2)
char_name_letters[c] = true;
}
- else if (w1 == "online_txt_filename")
+ else if (w1 == "online_txt_filename"_s)
{
online_txt_filename = w2;
}
- else if (w1 == "online_html_filename")
+ else if (w1 == "online_html_filename"_s)
{
online_html_filename = w2;
}
- else if (w1 == "online_sorting_option")
+ else if (w1 == "online_sorting_option"_s)
{
online_sorting_option = atoi(w2.c_str());
}
- else if (w1 == "online_gm_display_min_level")
- { // minimum GM level to display 'GM' when we want to display it
- online_gm_display_min_level = atoi(w2.c_str());
- if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough
- online_gm_display_min_level = 5;
+ else if (w1 == "online_gm_display_min_level"_s)
+ {
+ // minimum GM level to display 'GM' when we want to display it
+ return extract(w2, &online_gm_display_min_level);
}
- else if (w1 == "online_refresh_html")
+ else if (w1 == "online_refresh_html"_s)
{
online_refresh_html = atoi(w2.c_str());
if (online_refresh_html < 1)
online_refresh_html = 1;
}
- else if (w1 == "anti_freeze_enable")
+ else if (w1 == "anti_freeze_enable"_s)
{
anti_freeze_enable = config_switch(w2);
}
- else if (w1 == "anti_freeze_interval")
+ else if (w1 == "anti_freeze_interval"_s)
{
anti_freeze_interval = std::max(
std::chrono::seconds(atoi(w2.c_str())),
- std::chrono::seconds(5));
+ 5_s);
}
else
{
@@ -2859,7 +3074,7 @@ void term_func(void)
delete_session(login_session);
delete_session(char_session);
- CHAR_LOG("----End of char-server (normal end with closing of all files).\n");
+ CHAR_LOG("----End of char-server (normal end with closing of all files).\n"_fmt);
}
static
@@ -2884,20 +3099,20 @@ int do_init(Slice<ZString> argv)
ZString argvi = argv.pop_front();
if (argvi.startswith('-'))
{
- if (argvi == "--help")
+ if (argvi == "--help"_s)
{
- PRINTF("Usage: %s [--help] [--version] [files...]\n",
+ PRINTF("Usage: %s [--help] [--version] [files...]\n"_fmt,
argv0);
exit(0);
}
- else if (argvi == "--version")
+ else if (argvi == "--version"_s)
{
- PRINTF("%s\n", CURRENT_VERSION_STRING);
+ PRINTF("%s\n"_fmt, CURRENT_VERSION_STRING);
exit(0);
}
else
{
- FPRINTF(stderr, "Unknown argument: %s\n", argvi);
+ FPRINTF(stderr, "Unknown argument: %s\n"_fmt, argvi);
runflag = false;
}
}
@@ -2909,11 +3124,11 @@ int do_init(Slice<ZString> argv)
}
if (!loaded_config_yet)
- runflag &= load_config_file("conf/tmwa-char.conf", char_confs);
+ runflag &= load_config_file("conf/tmwa-char.conf"_s, char_confs);
// a newline in the log...
- CHAR_LOG("");
- CHAR_LOG("The char-server starting...\n");
+ CHAR_LOG(""_fmt);
+ CHAR_LOG("The char-server starting...\n"_fmt);
runflag &= lan_check();
@@ -2925,13 +3140,13 @@ int do_init(Slice<ZString> argv)
char_session = make_listen_port(char_port, SessionParsers{parse_char, delete_char});
- Timer(gettick() + std::chrono::seconds(1),
+ Timer(gettick() + 1_s,
check_connect_login_server,
- std::chrono::seconds(10)
+ 10_s
).detach();
- Timer(gettick() + std::chrono::seconds(1),
+ Timer(gettick() + 1_s,
send_users_tologin,
- std::chrono::seconds(5)
+ 5_s
).detach();
Timer(gettick() + autosave_time,
mmo_char_sync_timer,
@@ -2940,17 +3155,18 @@ int do_init(Slice<ZString> argv)
if (anti_freeze_enable > 0)
{
- Timer(gettick() + std::chrono::seconds(1),
+ Timer(gettick() + 1_s,
map_anti_freeze_system,
anti_freeze_interval
).detach();
}
- CHAR_LOG("The char-server is ready (Server is listening on the port %d).\n",
- char_port);
+ CHAR_LOG("The char-server is ready (Server is listening on the port %d).\n"_fmt,
+ char_port);
- PRINTF("The char-server is " SGR_BOLD SGR_GREEN "ready" SGR_RESET " (Server is listening on the port %d).\n\n",
- char_port);
+ PRINTF("The char-server is " SGR_BOLD SGR_GREEN "ready" SGR_RESET " (Server is listening on the port %d).\n\n"_fmt,
+ char_port);
return 0;
}
+} // namespace tmwa
diff --git a/src/char/char.hpp b/src/char/char.hpp
index 4c11073..a9c786f 100644
--- a/src/char/char.hpp
+++ b/src/char/char.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_CHAR_CHAR_HPP
-#define TMWA_CHAR_CHAR_HPP
+#pragma once
// char.hpp - Character server.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,15 +20,19 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../strings/fwd.hpp"
+#include "../strings/fwd.hpp"
-# include "../mmo/ip.hpp"
-# include "../mmo/mmo.hpp"
+#include "../generic/array.hpp"
-struct Session;
+#include "../net/ip.hpp"
+#include "../mmo/mmo.hpp"
+
+
+namespace tmwa
+{
constexpr int MAX_MAP_SERVERS = 30;
struct mmo_map_server
@@ -41,16 +44,13 @@ struct mmo_map_server
};
const CharPair *search_character(CharName character_name);
-const CharPair *search_character_id(int char_id);
+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);
-# define CHAR_LOG(fmt, ...) \
+#define CHAR_LOG(fmt, ...) \
char_log(STRPRINTF(fmt, ## __VA_ARGS__))
-
-#endif // TMWA_CHAR_CHAR_HPP
+} // namespace tmwa
diff --git a/src/char/fwd.hpp b/src/char/fwd.hpp
new file mode 100644
index 0000000..31cd1ba
--- /dev/null
+++ b/src/char/fwd.hpp
@@ -0,0 +1,27 @@
+#pragma once
+// char/fwd.hpp - list of type names for char server
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../sanity.hpp"
+
+
+namespace tmwa
+{
+// meh, add more when I feel like it
+} // namespace tmwa
diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp
index c9965dc..c9ab5a4 100644
--- a/src/char/int_party.cpp
+++ b/src/char/int_party.cpp
@@ -20,8 +20,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-#include <cstdlib>
-#include <cstring>
+#include "../ints/udl.hpp"
#include "../strings/mstring.hpp"
#include "../strings/astring.hpp"
@@ -32,50 +31,58 @@
#include "../io/cxxstdio.hpp"
#include "../io/lock.hpp"
#include "../io/read.hpp"
+#include "../io/write.hpp"
+
+#include "../net/packets.hpp"
+
+#include "../proto2/char-map.hpp"
#include "../mmo/extract.hpp"
+#include "../mmo/ids.hpp"
#include "../mmo/mmo.hpp"
-#include "../mmo/socket.hpp"
#include "char.hpp"
#include "inter.hpp"
#include "../poison.hpp"
-AString party_txt = "save/party.txt";
+
+namespace tmwa
+{
+AString party_txt = "save/party.txt"_s;
static
-Map<int, struct party> party_db;
+Map<PartyId, PartyMost> party_db;
static
-int party_newid = 100;
+PartyId party_newid = wrap<PartyId>(100_u32);
static
-void mapif_party_broken(int party_id, int flag);
+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, int party_id, int account_id);
+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",
- p->party_id,
+ "%d,%d\t"_fmt,
+ p.party_id,
p->name,
p->exp, p->item);
for (int i = 0; i < MAX_PARTY; i++)
{
- struct party_member *m = &p->member[i];
+ PartyMember *m = &p->member[i];
if (!m->account_id)
continue;
str += STRPRINTF(
"%d,%d\t"
- "%s\t",
+ "%s\t"_fmt,
m->account_id, m->leader,
m->name);
}
@@ -84,9 +91,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
@@ -95,7 +102,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))
@@ -107,7 +114,7 @@ bool extract(XString str, party *p)
for (int i = 0; begin != end && i < MAX_PARTY; ++i)
{
- struct party_member *m = &p->member[i];
+ PartyMember *m = &p->member[i];
if (begin == end || !extract(*begin, record<','>(&m->account_id, &m->leader)))
return false;
@@ -123,7 +130,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++)
{
@@ -132,13 +139,13 @@ void party_check_deleted_init(struct party *p)
const CharPair *c = search_character(p->member[i].name);
if (!c || c->key.account_id != p->member[i].account_id)
{
- CHAR_LOG("WARNING: deleting obsolete party member %d %s of %d %s\n",
+ 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);
- PRINTF("WARNING: deleting obsolete party member %d %s of %d %s\n",
+ 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->member[i] = party_member{};
+ p.party_id, p->name);
+ p->member[i] = PartyMember{};
}
}
}
@@ -150,31 +157,33 @@ void inter_party_init(void)
if (!in.is_open())
return;
- // TODO: convert to use char_id, and change to extract()
+ // TODO: convert to use char_id
AString line;
int c = 0;
while (in.getline(line))
{
- int i, j = 0;
- if (SSCANF(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0
- && party_newid <= i)
+ PartyId i;
+ if (extract(line, record<'\t'>(&i, "%newid%"_s))
+ && party_newid < i)
{
party_newid = i;
continue;
}
- struct party p {};
- if (extract(line, &p) && p.party_id > 0)
+ PartyMost pm;
+ PartyPair pp;
+ pp.party_most = &pm;
+ if (extract(line, &pp) && pp.party_id)
{
- if (p.party_id >= party_newid)
- party_newid = p.party_id + 1;
- 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
{
- PRINTF("int_party: broken data [%s] line %d\n", party_txt,
+ PRINTF("int_party: broken data [%s] line %d\n"_fmt, party_txt,
c + 1);
}
c++;
@@ -183,7 +192,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);
@@ -195,19 +204,24 @@ int inter_party_save(void)
io::WriteLock fp(party_txt);
if (!fp.is_open())
{
- PRINTF("int_party: cant write [%s] !!! data is lost !!!\n",
+ PRINTF("int_party: cant write [%s] !!! data is lost !!!\n"_fmt,
party_txt);
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;
@@ -215,18 +229,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;
@@ -247,34 +266,32 @@ int party_check_exp_share(struct party *p)
}
// パーティが空かどうかチェック
-int party_check_empty(struct party *p)
+int party_check_empty(PartyPair p)
{
int i;
-// PRINTF("party check empty %08X\n", (int)p);
for (i = 0; i < MAX_PARTY; i++)
{
-// PRINTF("%d acc=%d\n", i, p->member[i].account_id);
- if (p->member[i].account_id > 0)
+ if (p->member[i].account_id)
{
return 0;
}
}
// 誰もいないので解散
- 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,
- int party_id, int account_id, CharName nick)
+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++)
@@ -283,20 +300,25 @@ void party_check_conflict_sub(struct party *p,
&& p->member[i].name == nick)
{
// 別のパーティに偽の所属データがあるので脱退
- PRINTF("int_party: party conflict! %d %d %d\n", account_id,
- party_id, p->party_id);
- mapif_parse_PartyLeave(nullptr, p->party_id, account_id);
+ 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);
}
}
}
// キャラの競合がないかチェック
static
-void party_check_conflict(int party_id, int account_id, CharName nick)
+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,140 +326,156 @@ void party_check_conflict(int party_id, int account_id, CharName nick)
// パーティ作成可否
static
-void mapif_party_created(Session *s, int account_id, struct party *p)
+void mapif_party_created(Session *s, AccountId account_id, PartyPair p)
{
- WFIFOW(s, 0) = 0x3820;
- WFIFOL(s, 2) = 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) = p->party_id;
- WFIFO_STRING(s, 11, p->name, 24);
- PRINTF("int_party: created! %d %s\n", 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", 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, int party_id)
+void mapif_party_noinfo(Session *s, PartyId party_id)
{
- WFIFOW(s, 0) = 0x3821;
- WFIFOW(s, 2) = 8;
- WFIFOL(s, 4) = party_id;
- WFIFOSET(s, 8);
- PRINTF("int_party: info not found %d\n", party_id);
+ 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));
-// PRINTF("int_party: info %d %s\n", p->party_id, p->name);
+ {
+ send_opacket<0x3821, 8, sizeof(NetPacket_Option<0x3821>)>(s, head_21, true, option_21);
+ }
}
// パーティメンバ追加可否
static
-void mapif_party_memberadded(Session *s, int party_id, int account_id, int flag)
+void mapif_party_memberadded(Session *s, PartyId party_id, AccountId account_id, int flag)
{
- WFIFOW(s, 0) = 0x3822;
- WFIFOL(s, 2) = party_id;
- WFIFOL(s, 6) = 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, int 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) = p->party_id;
- WBUFL(buf, 6) = 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", 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);
}
// パーティ脱退通知
static
-void mapif_party_leaved(int party_id, int account_id, CharName name)
+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) = party_id;
- WBUFL(buf, 6) = account_id;
- WBUF_STRING(buf, 10, name.to__actual(), 24);
- mapif_sendall(buf, 34);
- PRINTF("int_party: party leaved %d %d %s\n", party_id, account_id, name);
+ 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) = p->party_id;
- WBUFL(buf, 6) = 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(int party_id, int flag)
-{
- unsigned char buf[7];
- WBUFW(buf, 0) = 0x3826;
- WBUFL(buf, 2) = party_id;
- WBUFB(buf, 6) = flag;
- mapif_sendall(buf, 7);
- PRINTF("int_party: broken %d\n", party_id);
- CHAR_LOG("int_party: broken %d\n", party_id);
+void mapif_party_broken(PartyId party_id, int flag)
+{
+ 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);
}
// パーティ内発言
static
-void mapif_party_message(int party_id, int account_id, XString mes)
+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) = party_id;
- WBUFL(buf, 8) = 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);
+ }
}
//-------------------------------------------------------------------
@@ -445,26 +483,29 @@ void mapif_party_message(int party_id, int account_id, XString mes)
// パーティ
static
-void mapif_parse_CreateParty(Session *s, int account_id, PartyName name, CharName nick,
+void mapif_parse_CreateParty(Session *s, AccountId account_id, PartyName name, CharName nick,
MapName map, int lv)
{
{
if (!name.is_print())
{
- PRINTF("int_party: illegal party name [%s]\n", name);
- mapif_party_created(s, account_id, NULL);
+ PRINTF("int_party: illegal party name [%s]\n"_fmt, name);
+ 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", name);
- mapif_party_created(s, account_id, NULL);
+ PRINTF("int_party: same name party exists [%s]\n"_fmt, name);
+ mapif_party_created(s, account_id, PartyPair());
return;
}
- struct party p {};
- p.party_id = party_newid++;
+ PartyMost p {};
+ PartyPair pp;
+ pp.party_most = &p;
+ party_newid = next(party_newid);
+ pp.party_id = party_newid;
p.name = name;
p.exp = 0;
p.item = 0;
@@ -475,18 +516,19 @@ void mapif_parse_CreateParty(Session *s, int account_id, PartyName name, CharNam
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, int party_id)
+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);
@@ -494,11 +536,12 @@ void mapif_parse_PartyInfo(Session *s, int party_id)
// パーティ追加要求
static
-void mapif_parse_PartyAddMember(Session *s, int party_id, int account_id,
+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;
@@ -506,7 +549,7 @@ void mapif_parse_PartyAddMember(Session *s, int party_id, int account_id,
for (int i = 0; i < MAX_PARTY; i++)
{
- if (p->member[i].account_id == 0)
+ if (!p->member[i].account_id)
{
int flag = 0;
@@ -525,7 +568,7 @@ void mapif_parse_PartyAddMember(Session *s, int party_id, int account_id,
flag = 0x01;
}
if (flag)
- mapif_party_optionchanged(s, p, 0, 0);
+ mapif_party_optionchanged(s, p, AccountId(), 0);
return;
}
}
@@ -534,11 +577,12 @@ void mapif_parse_PartyAddMember(Session *s, int party_id, int account_id,
// パーティー設定変更要求
static
-void mapif_parse_PartyChangeOption(Session *s, int party_id, int account_id,
+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;
@@ -555,9 +599,10 @@ void mapif_parse_PartyChangeOption(Session *s, int party_id, int account_id,
}
// パーティ脱退要求
-void mapif_parse_PartyLeave(Session *, int party_id, int account_id)
+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++)
@@ -566,7 +611,7 @@ void mapif_parse_PartyLeave(Session *, int party_id, int account_id)
continue;
mapif_party_leaved(party_id, account_id, p->member[i].name);
- p->member[i] = party_member{};
+ p->member[i] = PartyMember{};
if (party_check_empty(p) == 0)
mapif_party_info(nullptr, p); // まだ人がいるのでデータ送信
return;
@@ -575,11 +620,12 @@ void mapif_parse_PartyLeave(Session *, int party_id, int account_id)
// パーティマップ更新要求
static
-void mapif_parse_PartyChangeMap(Session *s, int party_id, int account_id,
+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++)
@@ -599,33 +645,21 @@ void mapif_parse_PartyChangeMap(Session *s, int party_id, int account_id,
flag = 1;
}
if (flag)
- mapif_party_optionchanged(s, p, 0, 0);
+ mapif_party_optionchanged(s, p, AccountId(), 0);
return;
}
}
-// パーティ解散要求
-static
-void mapif_parse_BreakParty(Session *, int party_id)
-{
- struct party *p = party_db.search(party_id);
- if (p == NULL)
- return;
-
- party_db.erase(party_id);
- mapif_party_broken(party_id, 0 /*unknown*/);
-}
-
// パーティメッセージ送信
static
-void mapif_parse_PartyMessage(Session *, int party_id, int account_id, XString mes)
+void mapif_parse_PartyMessage(Session *, PartyId party_id, AccountId account_id, XString mes)
{
mapif_party_message(party_id, account_id, mes);
}
// パーティチェック要求
static
-void mapif_parse_PartyCheck(Session *, int party_id, int account_id, CharName nick)
+void mapif_parse_PartyCheck(Session *, PartyId party_id, AccountId account_id, CharName nick)
{
party_check_conflict(party_id, account_id, nick);
}
@@ -635,121 +669,157 @@ void mapif_parse_PartyCheck(Session *, int party_id, int account_id, CharName ni
// ・パケット長データは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:
{
- int account = 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:
{
- int party_id = 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:
{
- int party_id = RFIFOL(ms, 2);
- int account_id = 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:
{
- int party_id = RFIFOL(ms, 2);
- int account_id = 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:
{
- int party_id = RFIFOL(ms, 2);
- int account_id = 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:
{
- int party_id = RFIFOL(ms, 2);
- int account_id = 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:
- {
- int party_id = RFIFOL(ms, 2);
- mapif_parse_BreakParty(ms, party_id);
}
- break;
case 0x3027:
{
- size_t len = RFIFOW(ms, 2) - 12;
- int party_id = RFIFOL(ms, 4);
- int account_id = 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:
{
- int party_id = RFIFOL(ms, 2);
- int account_id = 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;
}
// サーバーから脱退要求(キャラ削除用)
-void inter_party_leave(int party_id, int account_id)
+void inter_party_leave(PartyId party_id, AccountId account_id)
{
mapif_parse_PartyLeave(nullptr, party_id, account_id);
}
+} // namespace tmwa
diff --git a/src/char/int_party.hpp b/src/char/int_party.hpp
index 1608c37..f33fc0d 100644
--- a/src/char/int_party.hpp
+++ b/src/char/int_party.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_CHAR_INT_PARTY_HPP
-#define TMWA_CHAR_INT_PARTY_HPP
+#pragma once
// int_party.hpp - Internal party handling.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,19 +20,23 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../strings/fwd.hpp"
+#include "../strings/fwd.hpp"
-struct Session;
+#include "../net/fwd.hpp"
+#include "../mmo/fwd.hpp"
+
+
+namespace tmwa
+{
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(int party_id, int account_id);
+void inter_party_leave(PartyId party_id, AccountId account_id);
extern AString party_txt;
-
-#endif // TMWA_CHAR_INT_PARTY_HPP
+} // namespace tmwa
diff --git a/src/char/int_storage.cpp b/src/char/int_storage.cpp
index c7c1343..01665ec 100644
--- a/src/char/int_storage.cpp
+++ b/src/char/int_storage.cpp
@@ -20,50 +20,54 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-#include <cstdlib>
-#include <cstring>
-
-#include <functional>
-
#include "../strings/mstring.hpp"
#include "../strings/astring.hpp"
#include "../strings/xstring.hpp"
+#include "../strings/literal.hpp"
#include "../generic/db.hpp"
#include "../io/cxxstdio.hpp"
#include "../io/lock.hpp"
#include "../io/read.hpp"
+#include "../io/write.hpp"
+
+#include "../net/packets.hpp"
+
+#include "../proto2/char-map.hpp"
#include "../mmo/extract.hpp"
#include "../mmo/mmo.hpp"
-#include "../mmo/socket.hpp"
#include "../poison.hpp"
+
+namespace tmwa
+{
// ファイル名のデフォルト
// inter_config_read()で再設定される
-AString storage_txt = "save/storage.txt";
+AString storage_txt = "save/storage.txt"_s;
static
-Map<int, 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(
- "%d,%d\t",
+ "%d,%d\t"_fmt,
p->account_id, p->storage_amount);
int f = 0;
- for (int i = 0; i < MAX_STORAGE; i++)
+ for (SOff0 i : SOff0::iter())
+ {
if (p->storage_[i].nameid && p->storage_[i].amount)
{
str += STRPRINTF(
- "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ",
- p->storage_[i].id,
+ "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d "_fmt,
+ 0 /*id*/,
p->storage_[i].nameid,
p->storage_[i].amount,
p->storage_[i].equip,
@@ -77,6 +81,7 @@ AString storage_tostr(struct storage *p)
// shouldn't that include 'broken' also? Oh, well ...
f++;
}
+ }
str += '\t';
@@ -87,9 +92,9 @@ 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;
+ std::vector<Item> storage_items;
if (!extract(str,
record<'\t'>(
record<','>(
@@ -98,7 +103,7 @@ bool extract(XString str, struct storage *p)
vrec<' '>(&storage_items))))
return false;
- if (p->account_id <= 0)
+ if (!p->account_id)
return false;
if (storage_items.size() > MAX_STORAGE)
@@ -106,15 +111,15 @@ bool extract(XString str, struct storage *p)
std::copy(storage_items.begin(), storage_items.end(), p->storage_.begin());
if (p->storage_amount != storage_items.size())
- PRINTF("WARNING: storage desync for %d\n", p->account_id);
+ PRINTF("WARNING: storage desync for %d\n"_fmt, p->account_id);
return true;
}
// アカウントから倉庫データインデックスを得る(新規倉庫追加可能)
-struct storage *account2storage(int account_id)
+Storage *account2storage(AccountId account_id)
{
- struct storage *s = storage_db.search(account_id);
- if (s == NULL)
+ Storage *s = storage_db.search(account_id);
+ if (s == nullptr)
{
s = storage_db.init(account_id);
s->account_id = account_id;
@@ -131,21 +136,21 @@ void inter_storage_init(void)
io::ReadFile in(storage_txt);
if (!in.is_open())
{
- PRINTF("cant't read : %s\n", storage_txt);
+ PRINTF("cant't read : %s\n"_fmt, storage_txt);
return;
}
AString line;
while (in.getline(line))
{
- struct storage s {};
+ Storage s {};
if (extract(line, &s))
{
storage_db.insert(s.account_id, s);
}
else
{
- PRINTF("int_storage: broken data [%s] line %d\n",
+ PRINTF("int_storage: broken data [%s] line %d\n"_fmt,
storage_txt, c);
}
c++;
@@ -153,7 +158,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)
@@ -168,7 +173,7 @@ int inter_storage_save(void)
if (!fp.is_open())
{
- PRINTF("int_storage: cant write [%s] !!! data is lost !!!\n",
+ PRINTF("int_storage: cant write [%s] !!! data is lost !!!\n"_fmt,
storage_txt);
return 1;
}
@@ -178,7 +183,7 @@ int inter_storage_save(void)
}
// 倉庫データ削除
-void inter_storage_delete(int account_id)
+void inter_storage_delete(AccountId account_id)
{
storage_db.erase(account_id);
}
@@ -188,54 +193,62 @@ void inter_storage_delete(int account_id)
// 倉庫データの送信
static
-void mapif_load_storage(Session *ss, int account_id)
+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) = 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, int account_id)
+void mapif_save_storage_ack(Session *ss, AccountId account_id)
{
- WFIFOW(ss, 0) = 0x3811;
- WFIFOL(ss, 2) = 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)
{
- mapif_load_storage(ss, 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;
- int account_id = RFIFOL(ss, 4);
- int len = RFIFOW(ss, 2);
- if (sizeof(struct storage) != len - 8)
- {
- PRINTF("inter storage: data size error %zu %d\n",
- 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 からの通信
@@ -243,18 +256,20 @@ 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;
}
+} // namespace tmwa
diff --git a/src/char/int_storage.hpp b/src/char/int_storage.hpp
index 7f6deb5..b8ec9db 100644
--- a/src/char/int_storage.hpp
+++ b/src/char/int_storage.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_CHAR_INT_STORAGE_HPP
-#define TMWA_CHAR_INT_STORAGE_HPP
+#pragma once
// int_storage.hpp - Internal storage handling.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,19 +20,23 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../strings/fwd.hpp"
+#include "../strings/fwd.hpp"
-struct Session;
+#include "../net/fwd.hpp"
+#include "../mmo/fwd.hpp"
+
+
+namespace tmwa
+{
void inter_storage_init(void);
int inter_storage_save(void);
-void inter_storage_delete(int account_id);
-struct storage *account2storage(int account_id);
+void inter_storage_delete(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;
-
-#endif // TMWA_CHAR_INT_STORAGE_HPP
+} // namespace tmwa
diff --git a/src/char/inter.cpp b/src/char/inter.cpp
index 204a0e2..1cf41ff 100644
--- a/src/char/inter.cpp
+++ b/src/char/inter.cpp
@@ -21,8 +21,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <cassert>
-#include <cstdlib>
-#include <cstring>
#include <vector>
@@ -30,18 +28,22 @@
#include "../strings/astring.hpp"
#include "../strings/zstring.hpp"
#include "../strings/xstring.hpp"
+#include "../strings/literal.hpp"
+#include "../generic/array.hpp"
#include "../generic/db.hpp"
#include "../io/cxxstdio.hpp"
#include "../io/lock.hpp"
#include "../io/read.hpp"
+#include "../io/write.hpp"
+
+#include "../net/packets.hpp"
+
+#include "../proto2/char-map.hpp"
-#include "../mmo/config_parse.hpp"
#include "../mmo/extract.hpp"
-#include "../mmo/socket.hpp"
-#include "../mmo/timer.hpp"
-#include "../mmo/utils.hpp"
+#include "../mmo/mmo.hpp"
#include "char.hpp"
#include "int_party.hpp"
@@ -49,34 +51,23 @@
#include "../poison.hpp"
+
+namespace tmwa
+{
static
-AString accreg_txt = "save/accreg.txt";
+AString accreg_txt = "save/accreg.txt"_s;
struct accreg
{
- int account_id, reg_num;
- Array<struct global_reg, ACCOUNT_REG_NUM> reg;
+ AccountId account_id;
+ int reg_num;
+ Array<GlobalReg, 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,
-};
-
//--------------------------------------------------------
// アカウント変数を文字列へ変換
@@ -85,9 +76,9 @@ AString inter_accreg_tostr(struct accreg *reg)
{
assert(reg->reg_num < ACCOUNT_REG_NUM);
MString str;
- str += STRPRINTF("%d\t", reg->account_id);
+ str += STRPRINTF("%d\t"_fmt, reg->account_id);
for (int j = 0; j < reg->reg_num; j++)
- str += STRPRINTF("%s,%d ", reg->reg[j].str, reg->reg[j].value);
+ str += STRPRINTF("%s,%d "_fmt, reg->reg[j].str, reg->reg[j].value);
return AString(str);
}
@@ -95,13 +86,13 @@ AString inter_accreg_tostr(struct accreg *reg)
static
bool extract(XString str, struct accreg *reg)
{
- std::vector<struct global_reg> vars;
+ std::vector<GlobalReg> vars;
if (!extract(str,
record<'\t'>(
&reg->account_id,
vrec<' '>(&vars))))
return false;
- if (reg->account_id <= 0)
+ if (!reg->account_id)
return false;
if (vars.size() > ACCOUNT_REG_NUM)
@@ -130,7 +121,7 @@ void inter_accreg_init(void)
}
else
{
- PRINTF("inter: accreg: broken data [%s] line %d\n", accreg_txt,
+ PRINTF("inter: accreg: broken data [%s] line %d\n"_fmt, accreg_txt,
c);
}
c++;
@@ -155,7 +146,7 @@ int inter_accreg_save(void)
io::WriteLock fp(accreg_txt);
if (!fp.is_open())
{
- PRINTF("int_accreg: cant write [%s] !!! data is lost !!!\n",
+ PRINTF("int_accreg: cant write [%s] !!! data is lost !!!\n"_fmt,
accreg_txt);
return 1;
}
@@ -168,19 +159,19 @@ int inter_accreg_save(void)
bool inter_config(XString w1, ZString w2)
{
{
- if (w1 == "storage_txt")
+ if (w1 == "storage_txt"_s)
{
storage_txt = w2;
}
- else if (w1 == "party_txt")
+ else if (w1 == "party_txt"_s)
{
party_txt = w2;
}
- else if (w1 == "accreg_txt")
+ else if (w1 == "accreg_txt"_s)
{
accreg_txt = w2;
}
- else if (w1 == "party_share_level")
+ else if (w1 == "party_share_level"_s)
{
party_share_level = atoi(w2.c_str());
if (party_share_level < 0)
@@ -218,14 +209,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 +222,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) = 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");
- 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 +330,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,68 +349,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)
{
- int id = RFIFOL(tms, 2), 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)
+ if (reg == nullptr)
{
- 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;
}
//--------------------------------------------------------
@@ -431,70 +449,42 @@ 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;
}
+} // namespace tmwa
diff --git a/src/char/inter.hpp b/src/char/inter.hpp
index 7d1a38b..19900f9 100644
--- a/src/char/inter.hpp
+++ b/src/char/inter.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_CHAR_INTER_HPP
-#define TMWA_CHAR_INTER_HPP
+#pragma once
// inter.hpp - Internal server.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,19 +20,19 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../strings/fwd.hpp"
+#include "../strings/fwd.hpp"
-struct Session;
+#include "../net/fwd.hpp"
+
+namespace tmwa
+{
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;
-
-#endif // TMWA_CHAR_INTER_HPP
+} // namespace tmwa
diff --git a/src/char/main.cpp b/src/char/main.cpp
index 6814574..6636196 100644
--- a/src/char/main.cpp
+++ b/src/char/main.cpp
@@ -1,4 +1,3 @@
-#include "char.hpp"
// char/main.cpp - dummy file to make Make dependencies work
//
// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
@@ -18,4 +17,11 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+#include "char.hpp"
+
#include "../poison.hpp"
+
+
+namespace tmwa
+{
+} // namespace tmwa