summaryrefslogtreecommitdiff
path: root/src/char/char.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/char/char.cpp')
-rw-r--r--src/char/char.cpp437
1 files changed, 96 insertions, 341 deletions
diff --git a/src/char/char.cpp b/src/char/char.cpp
index ff9905f..a9b6834 100644
--- a/src/char/char.cpp
+++ b/src/char/char.cpp
@@ -78,7 +78,11 @@
#include "../wire/packets.hpp"
+#include "char_conf.hpp"
+#include "char_lan_conf.hpp"
+#include "globals.hpp"
#include "inter.hpp"
+#include "inter_conf.hpp"
#include "int_party.hpp"
#include "int_storage.hpp"
@@ -87,52 +91,8 @@
namespace tmwa
{
-static
-Array<struct mmo_map_server, MAX_MAP_SERVERS> server;
-static
-Array<Session *, MAX_MAP_SERVERS> server_session;
-static
-Array<int, MAX_MAP_SERVERS> server_freezeflag; // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed
-static
-int anti_freeze_enable = 0;
-static
-std::chrono::seconds anti_freeze_interval = 6_s;
-
-static
-Session *login_session, *char_session;
-static
-AccountName userid;
-static
-AccountPass passwd;
-static
-ServerName server_name;
-static
-const CharName WISP_SERVER_NAME = stringish<CharName>("Server"_s);
-static
-IP4Address login_ip;
-static
-int login_port = 6900;
-static
-IP4Address char_ip;
-static
-int char_port = 6121;
-static
-AString char_txt;
-static
-CharName unknown_char_name = stringish<CharName>("Unknown"_s);
-static
-AString char_log_filename = "log/char.log"_s;
-//Added for lan support
-static
-IP4Address lan_map_ip = IP4_LOCALHOST;
-static
-IP4Mask lan_subnet = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST);
-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);
-
-
+namespace char_
+{
struct char_session_data : SessionData
{
AccountId account_id;
@@ -141,61 +101,15 @@ struct char_session_data : SessionData
unsigned short packet_tmw_version;
AccountEmail email;
};
+} // namespace char_
void SessionDeleter::operator()(SessionData *sd)
{
- really_delete1 static_cast<char_session_data *>(sd);
+ really_delete1 static_cast<char_::char_session_data *>(sd);
}
-struct AuthFifoEntry
+namespace char_
{
- AccountId account_id;
- CharId char_id;
- int login_id1, login_id2;
- IP4Address ip;
- int delflag;
- SEX sex;
- unsigned short packet_tmw_version;
-};
-static
-std::array<AuthFifoEntry, 256> auth_fifo;
-static
-auto auth_fifo_iter = auth_fifo.begin();
-
-static
-CharId char_id_count = wrap<CharId>(150000);
-static
-std::vector<CharPair> char_keys;
-static
-int max_connect_user = 0;
-static
-std::chrono::milliseconds autosave_time = DEFAULT_AUTOSAVE_INTERVAL;
-
-// Initial position (it's possible to set it in conf file)
-static
-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"_s;
-static
-AString online_html_filename = "online.html"_s;
-static
-int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer
-static
-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)
-static
-TimeT update_online; // to update online files when we receiving information from a server (not less than 8 seconds)
-
-static
-pid_t pid = 0; // For forked DB writes
-
auto iter_map_sessions() -> decltype(filter_iterator<Session *>(std::declval<Array<Session *, MAX_MAP_SERVERS> *>()))
{
@@ -241,7 +155,7 @@ void delete_frommap(Session *sess)
//------------------------------
void char_log(XString line)
{
- io::AppendFile logfp(char_log_filename, true);
+ io::AppendFile logfp(char_conf.char_log_filename, true);
if (!logfp.is_open())
return;
log_with_timestamp(logfp, line);
@@ -318,7 +232,7 @@ AString mmo_char_tostr(struct CharPair *cp)
// on multi-map server, sometimes it's posssible that last_point become void. (reason???) We check that to not lost character at restart.
if (!p->last_point.map_)
{
- p->last_point = start_point;
+ p->last_point = char_conf.start_point;
}
MString str_p;
@@ -405,12 +319,6 @@ AString mmo_char_tostr(struct CharPair *cp)
return AString(str_p);
}
-static
-bool impl_extract(XString str, Point *p)
-{
- return extract(str, record<','>(&p->map_, &p->x, &p->y));
-}
-
struct skill_loader
{
SkillID id;
@@ -429,6 +337,7 @@ bool impl_extract(XString str, struct skill_loader *s)
s->flags = SkillFlags(flags_and_level >> 16);
return true;
}
+} // namespace char
//-------------------------------------------------------------------------
// Function to set the character from the line (at read of characters file)
@@ -436,6 +345,8 @@ bool impl_extract(XString str, struct skill_loader *s)
static
bool impl_extract(XString str, CharPair *cp)
{
+ using namespace tmwa::char_;
+
CharKey *k = &cp->key;
CharData *p = cp->data.get();
@@ -523,6 +434,8 @@ bool impl_extract(XString str, CharPair *cp)
return true;
}
+namespace char_
+{
//---------------------------------
// Function to read characters file
//---------------------------------
@@ -532,11 +445,11 @@ int mmo_char_init(void)
char_keys.clear();
online_chars.clear();
- io::ReadFile in(char_txt);
+ io::ReadFile in(char_conf.char_txt);
if (!in.is_open())
{
- PRINTF("Characters file not found: %s.\n"_fmt, char_txt);
- CHAR_LOG("Characters file not found: %s.\n"_fmt, char_txt);
+ PRINTF("Characters file not found: %s.\n"_fmt, char_conf.char_txt);
+ CHAR_LOG("Characters file not found: %s.\n"_fmt, char_conf.char_txt);
CHAR_LOG("Id for the next created character: %d.\n"_fmt,
char_id_count);
return 0;
@@ -574,9 +487,9 @@ int mmo_char_init(void)
}
PRINTF("mmo_char_init: %zu characters read in %s.\n"_fmt,
- char_keys.size(), char_txt);
+ char_keys.size(), char_conf.char_txt);
CHAR_LOG("mmo_char_init: %zu characters read in %s.\n"_fmt,
- char_keys.size(), char_txt);
+ char_keys.size(), char_conf.char_txt);
CHAR_LOG("Id for the next created character: %d.\n"_fmt,
char_id_count);
@@ -590,7 +503,7 @@ int mmo_char_init(void)
static
void mmo_char_sync(void)
{
- io::WriteLock fp(char_txt);
+ io::WriteLock fp(char_conf.char_txt);
if (!fp.is_open())
{
PRINTF("WARNING: Server can't not save characters.\n"_fmt);
@@ -681,12 +594,14 @@ CharPair *make_new_char(Session *s, CharName name, const Stats6& stats, uint8_t
{
// only letters/symbols in char_name_letters are authorised
for (uint8_t c : name.to__actual())
- if (!char_name_letters[c])
+ {
+ if (!char_conf.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"_fmt,
s, sd->account_id, name, c);
return nullptr;
}
+ }
}
// TODO this comment is obsolete
@@ -800,8 +715,8 @@ CharPair *make_new_char(Session *s, CharName name, const Stats6& stats, uint8_t
cd.head_top = ItemNameId();
cd.head_mid = ItemNameId();
cd.head_bottom = ItemNameId();
- cd.last_point = start_point;
- cd.save_point = start_point;
+ cd.last_point = char_conf.start_point;
+ cd.save_point = char_conf.start_point;
char_keys.push_back(std::move(cp));
online_chars.push_back(nullptr);
@@ -815,10 +730,10 @@ static
void create_online_files(void)
{
// write files
- io::WriteFile fp(online_txt_filename);
+ io::WriteFile fp(char_conf.online_txt_filename);
if (fp.is_open())
{
- io::WriteFile fp2(online_html_filename);
+ io::WriteFile fp2(char_conf.online_html_filename);
if (fp2.is_open())
{
// get time
@@ -826,15 +741,15 @@ void create_online_files(void)
stamp_time(timetemp);
// write heading
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, " <META http-equiv=\"Refresh\" content=\"%d\">\n"_fmt, char_conf.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);
+ char_conf.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);
+ char_conf.server_name, timetemp);
+ FPRINTF(fp, "Online Players on %s (%s):\n"_fmt, char_conf.server_name, timetemp);
FPRINTF(fp, "\n"_fmt);
int players = 0;
@@ -870,14 +785,14 @@ void create_online_files(void)
// without/with 'GM' display
GmLevel gml = isGM(cd.key.account_id);
{
- if (gml.satisfies(online_gm_display_min_level))
+ if (gml.satisfies(char_conf.online_gm_display_min_level))
FPRINTF(fp, "%-24s (GM) "_fmt, cd.key.name);
else
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>"_fmt);
- if (gml.satisfies(online_gm_display_min_level))
+ if (gml.satisfies(char_conf.online_gm_display_min_level))
FPRINTF(fp2, "<b>"_fmt);
for (char c : cd.key.name.to__actual())
{
@@ -897,7 +812,7 @@ void create_online_files(void)
break;
};
}
- if (gml.satisfies(online_gm_display_min_level))
+ if (gml.satisfies(char_conf.online_gm_display_min_level))
FPRINTF(fp2, "</b> (GM)"_fmt);
FPRINTF(fp2, "</td>\n"_fmt);
}
@@ -1257,8 +1172,8 @@ void parse_tologin(Session *ls)
fixed_6c.code = 0x42;
send_fpacket<0x006c, 3>(s2, fixed_6c);
}
- else if (max_connect_user == 0
- || count_users() < max_connect_user)
+ else if (char_conf.max_connect_user == 0
+ || count_users() < char_conf.max_connect_user)
{
sd->email = stringish<AccountEmail>(fixed.email);
if (!e_mail_check(sd->email))
@@ -1812,7 +1727,7 @@ void parse_frommap(Session *ms)
server[id].users = head.users;
assert (head.users == repeat.size());
- if (anti_freeze_enable)
+ if (char_conf.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
for (Session *& oci : online_chars)
@@ -2234,7 +2149,7 @@ int search_mapserver(XString map)
static
int lan_ip_check(IP4Address addr)
{
- bool lancheck = lan_subnet.covers(addr);
+ bool lancheck = char_lan_conf.lan_subnet.covers(addr);
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);
@@ -2299,7 +2214,7 @@ void handle_x0066(Session *s, struct char_session_data *sd, uint8_t rfifob_2, IP
sd->account_id, ck->char_num, ip);
PRINTF("--Send IP of map-server. "_fmt);
if (lan_ip_check(ip))
- fixed_71.ip = lan_map_ip;
+ fixed_71.ip = char_lan_conf.lan_map_ip;
else
fixed_71.ip = server[i].ip;
fixed_71.port = server[i].port;
@@ -2403,8 +2318,8 @@ void parse_char(Session *s)
&& afi.delflag == 2)
{
afi.delflag = 1;
- if (max_connect_user == 0
- || count_users() < max_connect_user)
+ if (char_conf.max_connect_user == 0
+ || count_users() < char_conf.max_connect_user)
{
{
// there is always a login server
@@ -2615,8 +2530,8 @@ void parse_char(Session *s)
}
AccountName userid_ = fixed.account_name;
AccountPass passwd_ = fixed.account_pass;
- if (i == MAX_MAP_SERVERS || userid_ != userid
- || passwd_ != passwd)
+ if (i == MAX_MAP_SERVERS || userid_ != char_conf.userid
+ || passwd_ != char_conf.passwd)
{
fixed_f9.code = 3;
send_fpacket<0x2af9, 3>(s, fixed_f9);
@@ -2626,7 +2541,7 @@ void parse_char(Session *s)
fixed_f9.code = 0;
s->set_parsers(SessionParsers{.func_parse= parse_frommap, .func_delete= delete_frommap});
server_session[i] = s;
- if (anti_freeze_enable)
+ if (char_conf.anti_freeze_enable)
server_freezeflag[i] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed
// ignore fixed.unknown
server[i].ip = fixed.ip;
@@ -2714,19 +2629,19 @@ void check_connect_login_server(TimerData *, tick_t)
if (!login_session)
{
PRINTF("Attempt to connect to login-server...\n"_fmt);
- login_session = make_connection(login_ip, login_port,
+ login_session = make_connection(char_conf.login_ip, char_conf.login_port,
SessionParsers{.func_parse= parse_tologin, .func_delete= delete_tologin});
if (!login_session)
return;
realloc_fifo(login_session, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
Packet_Fixed<0x2710> fixed_10;
- fixed_10.account_name = userid;
- fixed_10.account_pass = passwd;
+ fixed_10.account_name = char_conf.userid;
+ fixed_10.account_pass = char_conf.passwd;
fixed_10.unknown = 0;
- fixed_10.ip = char_ip;
- fixed_10.port = char_port;
- fixed_10.server_name = server_name;
+ fixed_10.ip = char_conf.char_ip;
+ fixed_10.port = char_conf.char_port;
+ fixed_10.server_name = char_conf.server_name;
fixed_10.unknown2 = 0;
fixed_10.maintenance = 0;
fixed_10.is_new = 0;
@@ -2734,61 +2649,13 @@ void check_connect_login_server(TimerData *, tick_t)
}
}
-//-------------------------------------------
-// Reading Lan Support configuration by [Yor]
-//-------------------------------------------
-static
-bool char_lan_config(io::Spanned<XString> w1, io::Spanned<ZString> w2)
-{
- struct hostent *h = nullptr;
-
- {
- if (w1.data == "lan_map_ip"_s)
- {
- // Read map-server Lan IP Address
- h = gethostbyname(w2.data.c_str());
- if (h != nullptr)
- {
- lan_map_ip = IP4Address({
- static_cast<uint8_t>(h->h_addr[0]),
- static_cast<uint8_t>(h->h_addr[1]),
- static_cast<uint8_t>(h->h_addr[2]),
- static_cast<uint8_t>(h->h_addr[3]),
- });
- }
- else
- {
- PRINTF("Bad IP value: %s\n"_fmt, w2.data);
- return false;
- }
- PRINTF("LAN IP of map-server: %s.\n"_fmt, lan_map_ip);
- }
- else if (w1.data == "subnet"_s /*backward compatibility*/
- || w1.data == "lan_subnet"_s)
- {
- if (!extract(w2.data, &lan_subnet))
- {
- PRINTF("Bad IP mask: %s\n"_fmt, w2.data);
- return false;
- }
- PRINTF("Sub-network of the map-server: %s.\n"_fmt,
- lan_subnet);
- }
- else
- {
- return false;
- }
- }
- return true;
-}
-
static
bool lan_check()
{
// sub-network check of the map-server
{
PRINTF("LAN test of LAN IP of the map-server: "_fmt);
- if (!lan_ip_check(lan_map_ip))
+ if (!lan_ip_check(char_lan_conf.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"_fmt);
return false;
@@ -2799,144 +2666,46 @@ bool lan_check()
}
static
-bool char_config(io::Spanned<XString> w1, io::Spanned<ZString> w2)
+bool char_config(io::Spanned<XString> key, io::Spanned<ZString> value)
+{
+ return parse_char_conf(char_conf, key, value);
+}
+
+static
+bool char_lan_config(io::Spanned<XString> key, io::Spanned<ZString> value)
+{
+ return parse_char_lan_conf(char_lan_conf, key, value);
+}
+
+static
+bool inter_config(io::Spanned<XString> key, io::Spanned<ZString> value)
{
- struct hostent *h = nullptr;
+ return parse_inter_conf(inter_conf, key, value);
+}
+static
+bool char_confs(io::Spanned<XString> key, io::Spanned<ZString> value)
+{
+ if (key.data == "char_conf"_s)
{
- if (w1.data == "userid"_s)
- userid = stringish<AccountName>(w2.data);
- else if (w1.data == "passwd"_s)
- passwd = stringish<AccountPass>(w2.data);
- else if (w1.data == "server_name"_s)
- {
- server_name = stringish<ServerName>(w2.data);
- PRINTF("%s server has been intialized\n"_fmt, w2.data);
- }
- else if (w1.data == "login_ip"_s)
- {
- h = gethostbyname(w2.data.c_str());
- if (h != nullptr)
- {
- login_ip = IP4Address({
- static_cast<uint8_t>(h->h_addr[0]),
- static_cast<uint8_t>(h->h_addr[1]),
- static_cast<uint8_t>(h->h_addr[2]),
- static_cast<uint8_t>(h->h_addr[3]),
- });
- PRINTF("Login server IP address : %s -> %s\n"_fmt,
- w2.data, login_ip);
- }
- else
- {
- PRINTF("Bad IP value: %s\n"_fmt, w2.data);
- return false;
- }
- }
- else if (w1.data == "login_port"_s)
- {
- login_port = atoi(w2.data.c_str());
- }
- else if (w1.data == "char_ip"_s)
- {
- h = gethostbyname(w2.data.c_str());
- if (h != nullptr)
- {
- char_ip = IP4Address({
- static_cast<uint8_t>(h->h_addr[0]),
- static_cast<uint8_t>(h->h_addr[1]),
- static_cast<uint8_t>(h->h_addr[2]),
- static_cast<uint8_t>(h->h_addr[3]),
- });
- PRINTF("Character server IP address : %s -> %s\n"_fmt,
- w2.data, char_ip);
- }
- else
- {
- PRINTF("Bad IP value: %s\n"_fmt, w2.data);
- return false;
- }
- }
- else if (w1.data == "char_port"_s)
- {
- char_port = atoi(w2.data.c_str());
- }
- else if (w1.data == "char_txt"_s)
- {
- char_txt = w2.data;
- }
- else if (w1.data == "max_connect_user"_s)
- {
- max_connect_user = atoi(w2.data.c_str());
- if (max_connect_user < 0)
- max_connect_user = 0; // unlimited online players
- }
- else if (w1.data == "autosave_time"_s)
- {
- autosave_time = std::chrono::seconds(atoi(w2.data.c_str()));
- if (autosave_time <= std::chrono::seconds::zero())
- autosave_time = DEFAULT_AUTOSAVE_INTERVAL;
- }
- else if (w1.data == "start_point"_s)
- {
- extract(w2.data, &start_point);
- }
- else if (w1.data == "unknown_char_name"_s)
- {
- unknown_char_name = stringish<CharName>(w2.data);
- }
- else if (w1.data == "char_log_filename"_s)
- {
- char_log_filename = w2.data;
- }
- else if (w1.data == "char_name_letters"_s)
- {
- if (!w2.data)
- char_name_letters.reset();
- else
- for (uint8_t c : w2.data)
- char_name_letters[c] = true;
- }
- else if (w1.data == "online_txt_filename"_s)
- {
- online_txt_filename = w2.data;
- }
- else if (w1.data == "online_html_filename"_s)
- {
- online_html_filename = w2.data;
- }
- else if (w1.data == "online_gm_display_min_level"_s)
- {
- // minimum GM level to display 'GM' when we want to display it
- return extract(w2.data, &online_gm_display_min_level);
- }
- else if (w1.data == "online_refresh_html"_s)
- {
- online_refresh_html = atoi(w2.data.c_str());
- if (online_refresh_html < 1)
- online_refresh_html = 1;
- }
- else if (w1.data == "anti_freeze_enable"_s)
- {
- anti_freeze_enable = config_switch(w2.data);
- }
- else if (w1.data == "anti_freeze_interval"_s)
- {
- anti_freeze_interval = std::max(
- std::chrono::seconds(atoi(w2.data.c_str())),
- 5_s);
- }
- else
- {
- return false;
- }
+ return load_config_file(value.data, char_config);
}
-
- return true;
+ if (key.data == "char_lan_conf"_s)
+ {
+ return load_config_file(value.data, char_lan_config);
+ }
+ if (key.data == "inter_conf"_s)
+ {
+ return load_config_file(value.data, inter_config);
+ }
+ key.span.error("Unknown meta-key for char server"_s);
+ return false;
}
+} // namespace char_
void term_func(void)
{
+ using namespace tmwa::char_;
// write online players files with no player
std::fill(online_chars.begin(), online_chars.end(), nullptr);
create_online_files();
@@ -2954,24 +2723,9 @@ void term_func(void)
CHAR_LOG("----End of char-server (normal end with closing of all files).\n"_fmt);
}
-static
-bool char_confs(io::Spanned<XString> key, io::Spanned<ZString> value)
-{
- bool ok;
- ok = char_config(key, value);
- if (!ok)
- return ok;
- ok = char_lan_config(key, value);
- if (!ok)
- return ok;
- ok = inter_config(key, value);
- if (!ok)
- return ok;
- return ok;
-}
-
int do_init(Slice<ZString> argv)
{
+ using namespace tmwa::char_;
ZString argv0 = argv.pop_front();
bool loaded_config_yet = false;
@@ -3000,12 +2754,12 @@ int do_init(Slice<ZString> argv)
else
{
loaded_config_yet = true;
- runflag &= load_config_file(argvi, char_confs);
+ runflag &= load_config_file(argvi, char_::char_confs);
}
}
if (!loaded_config_yet)
- runflag &= load_config_file("conf/tmwa-char.conf"_s, char_confs);
+ runflag &= load_config_file("conf/tmwa-char.conf"_s, char_::char_confs);
// a newline in the log...
CHAR_LOG(""_fmt);
@@ -3019,7 +2773,7 @@ int do_init(Slice<ZString> argv)
update_online = TimeT::now();
create_online_files(); // update online players files at start of the server
- char_session = make_listen_port(char_port, SessionParsers{parse_char, delete_char});
+ char_session = make_listen_port(char_conf.char_port, SessionParsers{parse_char, delete_char});
Timer(gettick() + 1_s,
check_connect_login_server,
@@ -3029,25 +2783,26 @@ int do_init(Slice<ZString> argv)
send_users_tologin,
5_s
).detach();
- Timer(gettick() + autosave_time,
+ Timer(gettick() + char_conf.autosave_time,
mmo_char_sync_timer,
- autosave_time
+ char_conf.autosave_time
).detach();
- if (anti_freeze_enable > 0)
+ if (char_conf.anti_freeze_enable > 0)
{
Timer(gettick() + 1_s,
map_anti_freeze_system,
- anti_freeze_interval
+ char_conf.anti_freeze_interval
).detach();
}
CHAR_LOG("The char-server is ready (Server is listening on the port %d).\n"_fmt,
- char_port);
+ char_conf.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);
+ char_conf.char_port);
return 0;
}
+// namespace char_ ends before term_func and do_init
} // namespace tmwa