add Ep3 battle test with spectator

This commit is contained in:
Martin Michelsen
2023-09-21 10:05:10 -07:00
parent a8c7da70e0
commit 5b907d4413
6 changed files with 77295 additions and 48 deletions
+1 -1
View File
@@ -128,7 +128,7 @@ foreach(TestCase IN ITEMS ${TestCases})
add_test(
NAME ${TestCase}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_BINARY_DIR}/newserv replay-log ${TestCase} --config=${CMAKE_SOURCE_DIR}/tests/config.json --require-password=11111111 --require-access-key=111111111111)
COMMAND ${CMAKE_BINARY_DIR}/newserv replay-log ${TestCase} --config=${CMAKE_SOURCE_DIR}/tests/config.json --require-basic-credentials)
endforeach()
add_test(
+12 -7
View File
@@ -393,8 +393,7 @@ int main(int argc, char** argv) {
const char* input_filename = nullptr;
const char* output_filename = nullptr;
const char* system_filename = nullptr;
const char* replay_required_access_key = "";
const char* replay_required_password = "";
bool replay_require_basic_credentials = false;
uint32_t root_object_address = 0;
uint8_t domain = 1;
uint8_t subdomain = 0xFF;
@@ -480,10 +479,8 @@ int main(int argc, char** argv) {
skip_big_endian = true;
} else if (!strcmp(argv[x], "--json")) {
json = true;
} else if (!strncmp(argv[x], "--require-password=", 19)) {
replay_required_password = &argv[x][19];
} else if (!strncmp(argv[x], "--require-access-key=", 21)) {
replay_required_access_key = &argv[x][21];
} else if (!strcmp(argv[x], "--require-basic-credentials")) {
replay_require_basic_credentials = true;
} else if (!strncmp(argv[x], "--root-addr=", 12)) {
root_object_address = strtoul(&argv[x][12], nullptr, 16);
} else if (!strncmp(argv[x], "--config=", 9)) {
@@ -1683,7 +1680,7 @@ int main(int argc, char** argv) {
}
replay_session.reset(new ReplaySession(
base, log_f.get(), state, replay_required_access_key, replay_required_password));
base, log_f.get(), state, replay_require_basic_credentials));
replay_session->start();
} else if (behavior == Behavior::RUN_SERVER) {
@@ -1764,6 +1761,14 @@ int main(int argc, char** argv) {
config_log.info("Ready");
event_base_dispatch(base.get());
if (replay_session) {
// If in a replay session, run the event loop for a bit longer to make
// sure the server doesn't send anything unexpected after the end of
// the session.
auto tv = usecs_to_timeval(500000);
event_base_loopexit(base.get(), &tv);
event_base_dispatch(base.get());
}
config_log.info("Normal shutdown");
state->proxy_server.reset(); // Break reference cycle
+29 -27
View File
@@ -70,26 +70,30 @@ shared_ptr<ReplaySession::Event> ReplaySession::create_event(
return event;
}
static bool string_is_basic(const string& data) {
if (data.empty()) {
return true;
}
char ch = data[0];
for (size_t z = 1; z < data.size(); z++) {
if ((data[z] != ch) && (data[z] != 0)) {
return false;
}
}
return true;
}
void ReplaySession::check_for_password(shared_ptr<const Event> ev) const {
auto version = this->clients.at(ev->client_id)->version;
auto check_pw = [&](const string& pw) {
if (!this->required_password.empty() && !pw.empty() && (pw != this->required_password)) {
if (this->require_basic_credentials && !string_is_basic(pw)) {
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
throw runtime_error(string_printf("(ev-line %zu) sent password is incorrect", ev->line_num));
}
};
auto check_ak = [&](const string& ak) {
if (this->required_access_key.empty() || ak.empty()) {
return;
}
string ref_access_key;
if (version == GameVersion::DC || version == GameVersion::PC || version == GameVersion::PATCH) {
ref_access_key = this->required_access_key.substr(0, 8);
} else {
ref_access_key = this->required_access_key;
}
if (ak != ref_access_key) {
if (this->require_basic_credentials && !ak.empty() && !string_is_basic(ak)) {
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
throw runtime_error(string_printf("(ev-line %zu) sent access key is incorrect", ev->line_num));
}
@@ -245,7 +249,7 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
mask.client_key = 0;
break;
}
case 0x19: {
case 0x19:
if (mask_size == sizeof(S_ReconnectSplit_19)) {
auto& mask = check_size_t<S_ReconnectSplit_19>(mask_data, mask_size);
mask.pc_address = 0;
@@ -255,8 +259,7 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
mask.address = 0;
}
break;
}
case 0x41: {
case 0x41:
if (version == GameVersion::PC) {
auto& mask = check_size_t<S_GuildCardSearchResult_PC_41>(mask_data, mask_size);
mask.reconnect_command.address = 0;
@@ -268,8 +271,7 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
mask.reconnect_command.address = 0;
}
break;
}
case 0x64: {
case 0x64:
if (version == GameVersion::PC) {
auto& mask = check_size_t<S_JoinGame_PC_64>(mask_data, mask_size);
mask.variations.clear(0);
@@ -281,14 +283,18 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
mask.rare_seed = 0;
}
break;
}
case 0xB1: {
case 0xE8:
if (version == GameVersion::GC) {
auto& mask = check_size_t<S_JoinSpectatorTeam_GC_Ep3_E8>(mask_data, mask_size);
mask.rare_seed = 0;
}
break;
case 0xB1:
for (size_t x = 4; x < ev->mask.size(); x++) {
ev->mask[x] = 0;
}
break;
}
case 0xC9: {
case 0xC9:
if (mask_size == 0xCC) {
auto& mask = check_size_t<G_ServerVersionStrings_GC_Ep3_6xB4x46>(
mask_data, mask_size);
@@ -297,8 +303,7 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
mask.date_str2.clear(0);
}
break;
}
case 0x6C: {
case 0x6C:
if (version == GameVersion::GC && mask_size >= 0x14) {
const auto& cmd = check_size_t<G_MapList_GC_Ep3_6xB6x40>(cmd_data, cmd_size, 0xFFFF);
if ((cmd.header.header.basic_header.subcommand == 0xB6) &&
@@ -314,7 +319,6 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
}
}
break;
}
}
break;
}
@@ -361,11 +365,9 @@ ReplaySession::ReplaySession(
shared_ptr<struct event_base> base,
FILE* input_log,
shared_ptr<ServerState> state,
const string& required_access_key,
const string& required_password)
bool require_basic_credentials)
: state(state),
required_access_key(required_access_key),
required_password(required_password),
require_basic_credentials(require_basic_credentials),
base(base),
commands_sent(0),
bytes_sent(0),
+2 -4
View File
@@ -18,8 +18,7 @@ public:
std::shared_ptr<struct event_base> base,
FILE* input_log,
std::shared_ptr<ServerState> state,
const std::string& required_access_key = "",
const std::string& required_password = "");
bool require_basic_credentials);
ReplaySession(const ReplaySession&) = delete;
ReplaySession(ReplaySession&&) = delete;
ReplaySession& operator=(const ReplaySession&) = delete;
@@ -65,8 +64,7 @@ private:
};
std::shared_ptr<ServerState> state;
std::string required_access_key;
std::string required_password;
bool require_basic_credentials;
std::unordered_map<uint64_t, std::shared_ptr<Client>> clients;
std::unordered_map<Channel*, std::shared_ptr<Client>> channel_to_client;
+14 -9
View File
@@ -1431,29 +1431,34 @@ static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l)
cmd.leader_id = watched_lobby->leader_id;
// Live spectating
for (size_t z = 0; z < 4; z++) {
if (!watched_lobby->clients[z]) {
auto& wc = watched_lobby->clients[z];
if (!wc) {
continue;
}
auto& p = cmd.players[z];
p.lobby_data.player_tag = 0x00010000;
p.lobby_data.guild_card = watched_lobby->clients[z]->license->serial_number;
p.lobby_data.client_id = watched_lobby->clients[z]->lobby_client_id;
p.lobby_data.name = watched_lobby->clients[z]->game_data.player()->disp.name;
p.lobby_data.guild_card = wc->license->serial_number;
p.lobby_data.client_id = wc->lobby_client_id;
p.lobby_data.name = wc->game_data.player()->disp.name;
remove_language_marker_inplace(p.lobby_data.name);
p.inventory = watched_lobby->clients[z]->game_data.player()->inventory;
p.inventory = wc->game_data.player()->inventory;
for (size_t y = 0; y < 30; y++) {
p.inventory.items[y].data.bswap_data2_if_mag();
}
p.disp = watched_lobby->clients[z]->game_data.player()->disp.to_dcpcv3();
p.disp = wc->game_data.player()->disp.to_dcpcv3();
remove_language_marker_inplace(p.disp.visual.name);
auto& e = cmd.entries[z];
e.player_tag = 0x00010000;
e.guild_card_number = watched_lobby->clients[z]->license->serial_number;
e.name = watched_lobby->clients[z]->game_data.player()->disp.name;
e.guild_card_number = wc->license->serial_number;
e.name = wc->game_data.player()->disp.name;
remove_language_marker_inplace(e.name);
e.present = 1;
e.level = watched_lobby->clients[z]->game_data.player()->disp.stats.level.load();
e.level = wc->game_data.ep3_config
? (wc->game_data.ep3_config->online_clv_exp / 100)
: wc->game_data.player()->disp.stats.level.load();
e.unknown_a5.clear(0);
e.unknown_a6.clear(0);
player_count++;
}
File diff suppressed because it is too large Load Diff