add Ep3 battle test with spectator
This commit is contained in:
+1
-1
@@ -128,7 +128,7 @@ foreach(TestCase IN ITEMS ${TestCases})
|
|||||||
add_test(
|
add_test(
|
||||||
NAME ${TestCase}
|
NAME ${TestCase}
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
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()
|
endforeach()
|
||||||
|
|
||||||
add_test(
|
add_test(
|
||||||
|
|||||||
+12
-7
@@ -393,8 +393,7 @@ int main(int argc, char** argv) {
|
|||||||
const char* input_filename = nullptr;
|
const char* input_filename = nullptr;
|
||||||
const char* output_filename = nullptr;
|
const char* output_filename = nullptr;
|
||||||
const char* system_filename = nullptr;
|
const char* system_filename = nullptr;
|
||||||
const char* replay_required_access_key = "";
|
bool replay_require_basic_credentials = false;
|
||||||
const char* replay_required_password = "";
|
|
||||||
uint32_t root_object_address = 0;
|
uint32_t root_object_address = 0;
|
||||||
uint8_t domain = 1;
|
uint8_t domain = 1;
|
||||||
uint8_t subdomain = 0xFF;
|
uint8_t subdomain = 0xFF;
|
||||||
@@ -480,10 +479,8 @@ int main(int argc, char** argv) {
|
|||||||
skip_big_endian = true;
|
skip_big_endian = true;
|
||||||
} else if (!strcmp(argv[x], "--json")) {
|
} else if (!strcmp(argv[x], "--json")) {
|
||||||
json = true;
|
json = true;
|
||||||
} else if (!strncmp(argv[x], "--require-password=", 19)) {
|
} else if (!strcmp(argv[x], "--require-basic-credentials")) {
|
||||||
replay_required_password = &argv[x][19];
|
replay_require_basic_credentials = true;
|
||||||
} else if (!strncmp(argv[x], "--require-access-key=", 21)) {
|
|
||||||
replay_required_access_key = &argv[x][21];
|
|
||||||
} else if (!strncmp(argv[x], "--root-addr=", 12)) {
|
} else if (!strncmp(argv[x], "--root-addr=", 12)) {
|
||||||
root_object_address = strtoul(&argv[x][12], nullptr, 16);
|
root_object_address = strtoul(&argv[x][12], nullptr, 16);
|
||||||
} else if (!strncmp(argv[x], "--config=", 9)) {
|
} else if (!strncmp(argv[x], "--config=", 9)) {
|
||||||
@@ -1683,7 +1680,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
replay_session.reset(new ReplaySession(
|
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();
|
replay_session->start();
|
||||||
|
|
||||||
} else if (behavior == Behavior::RUN_SERVER) {
|
} else if (behavior == Behavior::RUN_SERVER) {
|
||||||
@@ -1764,6 +1761,14 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
config_log.info("Ready");
|
config_log.info("Ready");
|
||||||
event_base_dispatch(base.get());
|
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");
|
config_log.info("Normal shutdown");
|
||||||
state->proxy_server.reset(); // Break reference cycle
|
state->proxy_server.reset(); // Break reference cycle
|
||||||
|
|||||||
+29
-27
@@ -70,26 +70,30 @@ shared_ptr<ReplaySession::Event> ReplaySession::create_event(
|
|||||||
return 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 {
|
void ReplaySession::check_for_password(shared_ptr<const Event> ev) const {
|
||||||
auto version = this->clients.at(ev->client_id)->version;
|
auto version = this->clients.at(ev->client_id)->version;
|
||||||
|
|
||||||
auto check_pw = [&](const string& pw) {
|
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);
|
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));
|
throw runtime_error(string_printf("(ev-line %zu) sent password is incorrect", ev->line_num));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto check_ak = [&](const string& ak) {
|
auto check_ak = [&](const string& ak) {
|
||||||
if (this->required_access_key.empty() || ak.empty()) {
|
if (this->require_basic_credentials && !ak.empty() && !string_is_basic(ak)) {
|
||||||
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) {
|
|
||||||
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
|
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));
|
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;
|
mask.client_key = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x19: {
|
case 0x19:
|
||||||
if (mask_size == sizeof(S_ReconnectSplit_19)) {
|
if (mask_size == sizeof(S_ReconnectSplit_19)) {
|
||||||
auto& mask = check_size_t<S_ReconnectSplit_19>(mask_data, mask_size);
|
auto& mask = check_size_t<S_ReconnectSplit_19>(mask_data, mask_size);
|
||||||
mask.pc_address = 0;
|
mask.pc_address = 0;
|
||||||
@@ -255,8 +259,7 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
mask.address = 0;
|
mask.address = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case 0x41:
|
||||||
case 0x41: {
|
|
||||||
if (version == GameVersion::PC) {
|
if (version == GameVersion::PC) {
|
||||||
auto& mask = check_size_t<S_GuildCardSearchResult_PC_41>(mask_data, mask_size);
|
auto& mask = check_size_t<S_GuildCardSearchResult_PC_41>(mask_data, mask_size);
|
||||||
mask.reconnect_command.address = 0;
|
mask.reconnect_command.address = 0;
|
||||||
@@ -268,8 +271,7 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
mask.reconnect_command.address = 0;
|
mask.reconnect_command.address = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case 0x64:
|
||||||
case 0x64: {
|
|
||||||
if (version == GameVersion::PC) {
|
if (version == GameVersion::PC) {
|
||||||
auto& mask = check_size_t<S_JoinGame_PC_64>(mask_data, mask_size);
|
auto& mask = check_size_t<S_JoinGame_PC_64>(mask_data, mask_size);
|
||||||
mask.variations.clear(0);
|
mask.variations.clear(0);
|
||||||
@@ -281,14 +283,18 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
mask.rare_seed = 0;
|
mask.rare_seed = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case 0xE8:
|
||||||
case 0xB1: {
|
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++) {
|
for (size_t x = 4; x < ev->mask.size(); x++) {
|
||||||
ev->mask[x] = 0;
|
ev->mask[x] = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case 0xC9:
|
||||||
case 0xC9: {
|
|
||||||
if (mask_size == 0xCC) {
|
if (mask_size == 0xCC) {
|
||||||
auto& mask = check_size_t<G_ServerVersionStrings_GC_Ep3_6xB4x46>(
|
auto& mask = check_size_t<G_ServerVersionStrings_GC_Ep3_6xB4x46>(
|
||||||
mask_data, mask_size);
|
mask_data, mask_size);
|
||||||
@@ -297,8 +303,7 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
mask.date_str2.clear(0);
|
mask.date_str2.clear(0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case 0x6C:
|
||||||
case 0x6C: {
|
|
||||||
if (version == GameVersion::GC && mask_size >= 0x14) {
|
if (version == GameVersion::GC && mask_size >= 0x14) {
|
||||||
const auto& cmd = check_size_t<G_MapList_GC_Ep3_6xB6x40>(cmd_data, cmd_size, 0xFFFF);
|
const auto& cmd = check_size_t<G_MapList_GC_Ep3_6xB6x40>(cmd_data, cmd_size, 0xFFFF);
|
||||||
if ((cmd.header.header.basic_header.subcommand == 0xB6) &&
|
if ((cmd.header.header.basic_header.subcommand == 0xB6) &&
|
||||||
@@ -314,7 +319,6 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -361,11 +365,9 @@ ReplaySession::ReplaySession(
|
|||||||
shared_ptr<struct event_base> base,
|
shared_ptr<struct event_base> base,
|
||||||
FILE* input_log,
|
FILE* input_log,
|
||||||
shared_ptr<ServerState> state,
|
shared_ptr<ServerState> state,
|
||||||
const string& required_access_key,
|
bool require_basic_credentials)
|
||||||
const string& required_password)
|
|
||||||
: state(state),
|
: state(state),
|
||||||
required_access_key(required_access_key),
|
require_basic_credentials(require_basic_credentials),
|
||||||
required_password(required_password),
|
|
||||||
base(base),
|
base(base),
|
||||||
commands_sent(0),
|
commands_sent(0),
|
||||||
bytes_sent(0),
|
bytes_sent(0),
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ public:
|
|||||||
std::shared_ptr<struct event_base> base,
|
std::shared_ptr<struct event_base> base,
|
||||||
FILE* input_log,
|
FILE* input_log,
|
||||||
std::shared_ptr<ServerState> state,
|
std::shared_ptr<ServerState> state,
|
||||||
const std::string& required_access_key = "",
|
bool require_basic_credentials);
|
||||||
const std::string& required_password = "");
|
|
||||||
ReplaySession(const ReplaySession&) = delete;
|
ReplaySession(const ReplaySession&) = delete;
|
||||||
ReplaySession(ReplaySession&&) = delete;
|
ReplaySession(ReplaySession&&) = delete;
|
||||||
ReplaySession& operator=(const ReplaySession&) = delete;
|
ReplaySession& operator=(const ReplaySession&) = delete;
|
||||||
@@ -65,8 +64,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<ServerState> state;
|
std::shared_ptr<ServerState> state;
|
||||||
std::string required_access_key;
|
bool require_basic_credentials;
|
||||||
std::string required_password;
|
|
||||||
|
|
||||||
std::unordered_map<uint64_t, std::shared_ptr<Client>> clients;
|
std::unordered_map<uint64_t, std::shared_ptr<Client>> clients;
|
||||||
std::unordered_map<Channel*, std::shared_ptr<Client>> channel_to_client;
|
std::unordered_map<Channel*, std::shared_ptr<Client>> channel_to_client;
|
||||||
|
|||||||
+14
-9
@@ -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;
|
cmd.leader_id = watched_lobby->leader_id;
|
||||||
// Live spectating
|
// Live spectating
|
||||||
for (size_t z = 0; z < 4; z++) {
|
for (size_t z = 0; z < 4; z++) {
|
||||||
if (!watched_lobby->clients[z]) {
|
auto& wc = watched_lobby->clients[z];
|
||||||
|
if (!wc) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto& p = cmd.players[z];
|
auto& p = cmd.players[z];
|
||||||
p.lobby_data.player_tag = 0x00010000;
|
p.lobby_data.player_tag = 0x00010000;
|
||||||
p.lobby_data.guild_card = watched_lobby->clients[z]->license->serial_number;
|
p.lobby_data.guild_card = wc->license->serial_number;
|
||||||
p.lobby_data.client_id = watched_lobby->clients[z]->lobby_client_id;
|
p.lobby_data.client_id = wc->lobby_client_id;
|
||||||
p.lobby_data.name = watched_lobby->clients[z]->game_data.player()->disp.name;
|
p.lobby_data.name = wc->game_data.player()->disp.name;
|
||||||
remove_language_marker_inplace(p.lobby_data.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++) {
|
for (size_t y = 0; y < 30; y++) {
|
||||||
p.inventory.items[y].data.bswap_data2_if_mag();
|
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);
|
remove_language_marker_inplace(p.disp.visual.name);
|
||||||
|
|
||||||
auto& e = cmd.entries[z];
|
auto& e = cmd.entries[z];
|
||||||
e.player_tag = 0x00010000;
|
e.player_tag = 0x00010000;
|
||||||
e.guild_card_number = watched_lobby->clients[z]->license->serial_number;
|
e.guild_card_number = wc->license->serial_number;
|
||||||
e.name = watched_lobby->clients[z]->game_data.player()->disp.name;
|
e.name = wc->game_data.player()->disp.name;
|
||||||
remove_language_marker_inplace(e.name);
|
remove_language_marker_inplace(e.name);
|
||||||
e.present = 1;
|
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++;
|
player_count++;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user