rewrite proxy server to support multiple clients and integration with game server

This commit is contained in:
Martin Michelsen
2022-03-27 18:14:23 -07:00
parent d977cf0608
commit 2597da95bc
24 changed files with 1370 additions and 992 deletions
+129 -3
View File
@@ -14,14 +14,23 @@ using namespace std;
ServerShell::ServerShell(std::shared_ptr<struct event_base> base,
std::shared_ptr<ServerState> state) : Shell(base, state) { }
ServerShell::ServerShell(
shared_ptr<struct event_base> base,
shared_ptr<ServerState> state)
: Shell(base, state) { }
void ServerShell::print_prompt() {
fwrite("newserv> ", 9, 1, stdout);
fflush(stdout);
}
shared_ptr<ProxyServer::LinkedSession> ServerShell::get_proxy_session() {
if (!this->state->proxy_server.get()) {
throw runtime_error("the proxy server is disabled");
}
return this->state->proxy_server->get_session();
}
void ServerShell::execute_command(const string& command) {
// find the entry in the command table and run the command
size_t command_end = skip_non_whitespace(command, 0);
@@ -34,9 +43,11 @@ void ServerShell::execute_command(const string& command) {
} else if (command_name == "help") {
fprintf(stderr, "\
Commands:\n\
General commands:\n\
help\n\
You\'re reading it now.\n\
\n\
Server commands:\n\
exit (or ctrl+d)\n\
Shut down the server.\n\
reload <item> ...\n\
@@ -66,8 +77,32 @@ Commands:\n\
Song IDs are 0 through 51; the default song is -1.\n\
announce <message>\n\
Send an announcement message to all players.\n\
\n\
Proxy commands (these will only work when exactly one client is connected):\n\
sc <data>\n\
Send a command to the client.\n\
ss <data>\n\
Send a command to the server.\n\
chat <text>\n\
Send a chat message to the server.\n\
dchat <data>\n\
Send a chat message to the server with arbitrary data in it.\n\
info-board <text>\n\
Set your info board contents.\n\
info-board-data <data>\n\
Set your info board contents with arbitrary data.\n\
marker <color-id>\n\
Send a lobby marker message to the server.\n\
event <event-id>\n\
Send a lobby event update to yourself.\n\
ship\n\
Request the ship select menu from the server.\n\
");
// SERVER COMMANDS
} else if (command_name == "reload") {
auto types = split(command_args, ' ');
if (types.empty()) {
@@ -189,6 +224,97 @@ Commands:\n\
u16string message16 = decode_sjis(command_args);
send_text_message(this->state, message16.c_str());
// PROXY COMMANDS
} else if ((command_name == "sc") || (command_name == "ss")) {
auto session = this->get_proxy_session();
bool to_server = (command_name[1] == 's');
string data = parse_data_string(command_args);
if (data.size() & 3) {
throw invalid_argument("data size is not a multiple of 4");
}
if (data.size() == 0) {
throw invalid_argument("no data given");
}
uint16_t* size_field = reinterpret_cast<uint16_t*>(data.data() + 2);
*size_field = data.size();
session->send_to_end(data, to_server);
} else if ((command_name == "chat") || (command_name == "dchat")) {
auto session = this->get_proxy_session();
string data(12, '\0');
data[0] = 0x06;
data.push_back('\x09');
data.push_back('E');
if (command_name == "dchat") {
data += parse_data_string(command_args);
} else {
data += command_args;
}
data.push_back('\0');
data.resize((data.size() + 3) & (~3));
uint16_t* size_field = reinterpret_cast<uint16_t*>(data.data() + 2);
*size_field = data.size();
session->send_to_end(data, true);
} else if (command_name == "marker") {
auto session = this->get_proxy_session();
string data("\x89\x00\x04\x00", 4);
data[1] = stod(command_args);
session->send_to_end(data, true);
} else if (command_name == "event") {
auto session = this->get_proxy_session();
string data("\xDA\x00\x04\x00", 4);
data[1] = stod(command_args);
session->send_to_end(data, false);
} else if (command_name == "ship") {
auto session = this->get_proxy_session();
static const string data("\xA0\x00\x04\x00", 4);
session->send_to_end(data, true);
} else if ((command_name == "info-board") || (command_name == "info-board-data")) {
auto session = this->get_proxy_session();
string data(4, '\0');
data[0] = 0xD9;
if (command_name == "info-board-data") {
data += parse_data_string(command_args);
} else {
data += command_args;
}
data.push_back('\0');
data.resize((data.size() + 3) & (~3));
uint16_t* size_field = reinterpret_cast<uint16_t*>(data.data() + 2);
*size_field = data.size();
session->send_to_end(data, true);
} else if (command_name == "set-save-quests") {
auto session = this->get_proxy_session();
if (command_args == "on") {
session->save_quests = true;
} else if (command_args == "off") {
session->save_quests = false;
} else {
throw invalid_argument("argument must be \"on\" or \"off\"");
}
} else {
throw invalid_argument("unknown command; try \'help\'");
}