handle multiple subcommands in one top-level command
This commit is contained in:
@@ -2533,7 +2533,7 @@ static void on_6x_C9_CB(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
on_subcommand(s, l, c, command, flag, data);
|
on_subcommand_multi(s, l, c, command, flag, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_chat_generic(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
static void on_chat_generic(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||||
|
|||||||
@@ -1714,21 +1714,42 @@ subcommand_handler_t subcommand_handlers[0x100] = {
|
|||||||
/* 6xFF */ nullptr,
|
/* 6xFF */ nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
void on_subcommand(shared_ptr<ServerState> s, shared_ptr<Lobby> l,
|
void on_subcommand_multi(shared_ptr<ServerState> s, shared_ptr<Lobby> l,
|
||||||
shared_ptr<Client> c, uint8_t command, uint8_t flag, const string& data) {
|
shared_ptr<Client> c, uint8_t command, uint8_t flag, const string& data) {
|
||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
throw runtime_error("game command is empty");
|
throw runtime_error("game command is empty");
|
||||||
}
|
}
|
||||||
if (c->version() == GameVersion::DC && (c->flags & (Client::Flag::IS_TRIAL_EDITION | Client::Flag::IS_DC_V1_PROTOTYPE))) {
|
if (c->version() == GameVersion::DC && (c->flags & (Client::Flag::IS_TRIAL_EDITION | Client::Flag::IS_DC_V1_PROTOTYPE))) {
|
||||||
// TODO: We should convert these to non-trial formats and vice versa
|
// TODO: We should convert these to non-trial formats and vice versa
|
||||||
forward_subcommand(l, c, command, flag, std::move(data));
|
forward_subcommand(l, c, command, flag, data.data(), data.size());
|
||||||
} else {
|
} else {
|
||||||
uint8_t which = static_cast<uint8_t>(data[0]);
|
StringReader r(data);
|
||||||
auto fn = subcommand_handlers[which];
|
while (!r.eof()) {
|
||||||
if (fn) {
|
size_t size;
|
||||||
fn(s, l, c, command, flag, data);
|
const auto& header = r.get<G_UnusedHeader>(false);
|
||||||
} else {
|
if (header.size != 0) {
|
||||||
on_unimplemented(s, l, c, command, flag, data);
|
size = header.size << 2;
|
||||||
|
} else {
|
||||||
|
const auto& ext_header = r.get<G_ExtendedHeader<G_UnusedHeader>>(false);
|
||||||
|
size = ext_header.size;
|
||||||
|
if (size < 8) {
|
||||||
|
throw runtime_error("extended subcommand header has size < 8");
|
||||||
|
}
|
||||||
|
if (size & 3) {
|
||||||
|
throw runtime_error("extended subcommand size is not a multiple of 4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
throw runtime_error("invalid subcommand size");
|
||||||
|
}
|
||||||
|
const void* data = r.getv(size);
|
||||||
|
|
||||||
|
auto fn = subcommand_handlers[header.subcommand];
|
||||||
|
if (fn) {
|
||||||
|
fn(s, l, c, command, flag, data, size);
|
||||||
|
} else {
|
||||||
|
on_unimplemented(s, l, c, command, flag, data, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "PSOProtocol.hh"
|
#include "PSOProtocol.hh"
|
||||||
#include "ServerState.hh"
|
#include "ServerState.hh"
|
||||||
|
|
||||||
void on_subcommand(
|
void on_subcommand_multi(
|
||||||
std::shared_ptr<ServerState> s, std::shared_ptr<Lobby> l,
|
std::shared_ptr<ServerState> s, std::shared_ptr<Lobby> l,
|
||||||
std::shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
std::shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||||
const std::string& data);
|
const std::string& data);
|
||||||
|
|||||||
Reference in New Issue
Block a user