add some tools for ep3 replay
This commit is contained in:
@@ -37,6 +37,7 @@ enum BehaviorFlag : uint32_t {
|
|||||||
DISABLE_INTERFERENCE = 0x00000100,
|
DISABLE_INTERFERENCE = 0x00000100,
|
||||||
ALLOW_NON_COM_INTERFERENCE = 0x00000200,
|
ALLOW_NON_COM_INTERFERENCE = 0x00000200,
|
||||||
IS_TRIAL_EDITION = 0x00000400,
|
IS_TRIAL_EDITION = 0x00000400,
|
||||||
|
LOG_COMMANDS_IF_LOBBY_MISSING = 0x00000800,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StatSwapType : uint8_t {
|
enum class StatSwapType : uint8_t {
|
||||||
|
|||||||
+17
-14
@@ -256,7 +256,8 @@ void Server::send(const void* data, size_t size, uint8_t command, bool enable_ma
|
|||||||
l->battle_record->add_command(BattleRecord::Event::Type::BATTLE_COMMAND, data, size);
|
l->battle_record->add_command(BattleRecord::Event::Type::BATTLE_COMMAND, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (this->log().info("Generated command")) {
|
} else if ((this->options.behavior_flags & BehaviorFlag::LOG_COMMANDS_IF_LOBBY_MISSING) &&
|
||||||
|
this->log().info("Generated command")) {
|
||||||
print_data(stderr, data, size);
|
print_data(stderr, data, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1824,8 +1825,10 @@ const unordered_map<uint8_t, Server::handler_t> Server::subcommand_handlers({
|
|||||||
|
|
||||||
void Server::on_server_data_input(shared_ptr<Client> sender_c, const string& data) {
|
void Server::on_server_data_input(shared_ptr<Client> sender_c, const string& data) {
|
||||||
auto header = check_size_t<G_CardBattleCommandHeader>(data, 0xFFFF);
|
auto header = check_size_t<G_CardBattleCommandHeader>(data, 0xFFFF);
|
||||||
if (header.size * 4 < data.size()) {
|
size_t expected_size = header.size * 4;
|
||||||
throw runtime_error("command is incomplete");
|
if (expected_size < data.size()) {
|
||||||
|
print_data(stderr, data);
|
||||||
|
throw runtime_error(string_printf("command is incomplete: expected %zX bytes, received %zX bytes", expected_size, data.size()));
|
||||||
}
|
}
|
||||||
if (header.subcommand != 0xB3) {
|
if (header.subcommand != 0xB3) {
|
||||||
throw runtime_error("server data command is not 6xB3");
|
throw runtime_error("server data command is not 6xB3");
|
||||||
@@ -2163,33 +2166,29 @@ void Server::handle_CAx13_update_map_during_setup_t(shared_ptr<Client> c, const
|
|||||||
(this->map_and_rules->num_players == 0) &&
|
(this->map_and_rules->num_players == 0) &&
|
||||||
(this->registration_phase != RegistrationPhase::REGISTERED) &&
|
(this->registration_phase != RegistrationPhase::REGISTERED) &&
|
||||||
(this->registration_phase != RegistrationPhase::BATTLE_STARTED)) {
|
(this->registration_phase != RegistrationPhase::BATTLE_STARTED)) {
|
||||||
if (!this->last_chosen_map) {
|
|
||||||
throw runtime_error("CAx13 sent with no map chosen");
|
|
||||||
}
|
|
||||||
|
|
||||||
*this->map_and_rules = in_cmd.map_and_rules_state;
|
*this->map_and_rules = in_cmd.map_and_rules_state;
|
||||||
// The client will likely send incorrect values for the extended rules (or
|
// The client will likely send incorrect values for the extended rules (or
|
||||||
// in the case of NTE, no values at all, since the Rules structure is
|
// in the case of NTE, no values at all, since the Rules structure is
|
||||||
// smaller). So, use the values from the last chosen map if applicable, or
|
// smaller). So, use the values from the last chosen map if applicable, or
|
||||||
// the values from the $dicerange command if available.
|
// the values from the $dicerange command if available.
|
||||||
const auto& map_rules = this->last_chosen_map->version(c->language())->map->default_rules;
|
const Rules* map_rules = this->last_chosen_map ? &this->last_chosen_map->version(c->language())->map->default_rules : nullptr;
|
||||||
auto& server_rules = this->map_and_rules->rules;
|
auto& server_rules = this->map_and_rules->rules;
|
||||||
// NTE can specify the DEF dice value range in its Rules struct, so we use
|
// NTE can specify the DEF dice value range in its Rules struct, so we use
|
||||||
// that unless the map or $dicerange overrides it.
|
// that unless the map or $dicerange overrides it.
|
||||||
server_rules.def_dice_value_range = (map_rules.def_dice_value_range != 0xFF)
|
server_rules.def_dice_value_range = (map_rules && (map_rules->def_dice_value_range != 0xFF))
|
||||||
? map_rules.def_dice_value_range
|
? map_rules->def_dice_value_range
|
||||||
: (this->def_dice_value_range_override != 0xFF)
|
: (this->def_dice_value_range_override != 0xFF)
|
||||||
? this->def_dice_value_range_override
|
? this->def_dice_value_range_override
|
||||||
: this->options.is_nte()
|
: this->options.is_nte()
|
||||||
? server_rules.def_dice_value_range
|
? server_rules.def_dice_value_range
|
||||||
: 0;
|
: 0;
|
||||||
server_rules.atk_dice_value_range_2v1 = (map_rules.atk_dice_value_range_2v1 != 0xFF)
|
server_rules.atk_dice_value_range_2v1 = (map_rules && (map_rules->atk_dice_value_range_2v1 != 0xFF))
|
||||||
? map_rules.atk_dice_value_range_2v1
|
? map_rules->atk_dice_value_range_2v1
|
||||||
: (this->atk_dice_value_range_2v1_override != 0xFF)
|
: (this->atk_dice_value_range_2v1_override != 0xFF)
|
||||||
? this->atk_dice_value_range_2v1_override
|
? this->atk_dice_value_range_2v1_override
|
||||||
: 0;
|
: 0;
|
||||||
server_rules.def_dice_value_range_2v1 = (map_rules.def_dice_value_range_2v1 != 0xFF)
|
server_rules.def_dice_value_range_2v1 = (map_rules && (map_rules->def_dice_value_range_2v1 != 0xFF))
|
||||||
? map_rules.def_dice_value_range_2v1
|
? map_rules->def_dice_value_range_2v1
|
||||||
: (this->def_dice_value_range_2v1_override != 0xFF)
|
: (this->def_dice_value_range_2v1_override != 0xFF)
|
||||||
? this->def_dice_value_range_2v1_override
|
? this->def_dice_value_range_2v1_override
|
||||||
: 0;
|
: 0;
|
||||||
@@ -2585,6 +2584,10 @@ void Server::handle_CAx40_map_list_request(shared_ptr<Client> sender_c, const st
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Server::send_6xB6x41_to_all_clients() const {
|
void Server::send_6xB6x41_to_all_clients() const {
|
||||||
|
if (!this->last_chosen_map) {
|
||||||
|
throw logic_error("cannot send 6xB4x41 without a map chosen");
|
||||||
|
}
|
||||||
|
|
||||||
auto l = this->lobby.lock();
|
auto l = this->lobby.lock();
|
||||||
if (l) {
|
if (l) {
|
||||||
vector<string> map_commands_by_language;
|
vector<string> map_commands_by_language;
|
||||||
|
|||||||
+35
-14
@@ -2306,26 +2306,47 @@ Action a_replay_ep3_battle_commands(
|
|||||||
s->load_ep3_cards(false);
|
s->load_ep3_cards(false);
|
||||||
s->load_ep3_maps(false);
|
s->load_ep3_maps(false);
|
||||||
|
|
||||||
auto opt_rand_crypt = make_shared<PSOV2Encryption>(args.get<uint32_t>("seed", 0, Arguments::IntFormat::HEX));
|
int64_t base_seed = args.get<int64_t>("seed", -1);
|
||||||
Episode3::Server::Options options = {
|
bool is_trial = (get_cli_version(args, Version::GC_EP3) == Version::GC_EP3_NTE);
|
||||||
.card_index = s->ep3_card_index,
|
|
||||||
.map_index = s->ep3_map_index,
|
|
||||||
.behavior_flags = 0x0092,
|
|
||||||
.opt_rand_crypt = opt_rand_crypt,
|
|
||||||
.tournament = nullptr,
|
|
||||||
.trap_card_ids = {},
|
|
||||||
};
|
|
||||||
auto server = make_shared<Episode3::Server>(nullptr, std::move(options));
|
|
||||||
server->init();
|
|
||||||
|
|
||||||
auto input = read_input_data(args);
|
auto input = read_input_data(args);
|
||||||
auto lines = split(input, '\n');
|
vector<string> commands;
|
||||||
for (const auto& line : lines) {
|
for (const auto& line : split(input, '\n')) {
|
||||||
string data = parse_data_string(line);
|
string data = parse_data_string(line);
|
||||||
if (!data.empty()) {
|
if (!data.empty()) {
|
||||||
server->on_server_data_input(nullptr, data);
|
commands.emplace_back(std::move(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto run_replay = [&](int64_t seed, size_t) {
|
||||||
|
Episode3::Server::Options options = {
|
||||||
|
.card_index = s->ep3_card_index,
|
||||||
|
.map_index = s->ep3_map_index,
|
||||||
|
.behavior_flags = 0x0092,
|
||||||
|
.opt_rand_crypt = (seed >= 0) ? make_shared<PSOV2Encryption>(seed) : nullptr,
|
||||||
|
.tournament = nullptr,
|
||||||
|
.trap_card_ids = {},
|
||||||
|
};
|
||||||
|
if (is_trial) {
|
||||||
|
options.behavior_flags |= Episode3::BehaviorFlag::IS_TRIAL_EDITION;
|
||||||
|
}
|
||||||
|
if (base_seed >= 0) {
|
||||||
|
options.behavior_flags |= Episode3::BehaviorFlag::LOG_COMMANDS_IF_LOBBY_MISSING;
|
||||||
|
}
|
||||||
|
auto server = make_shared<Episode3::Server>(nullptr, std::move(options));
|
||||||
|
server->init();
|
||||||
|
for (const auto& command : commands) {
|
||||||
|
server->on_server_data_input(nullptr, command);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (base_seed >= 0) {
|
||||||
|
run_replay(base_seed, 0);
|
||||||
|
} else {
|
||||||
|
size_t num_threads = args.get<size_t>("threads", 0);
|
||||||
|
parallel_range<int64_t>(run_replay, 0, 0x100000000, num_threads);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Action a_run_server_replay_log(
|
Action a_run_server_replay_log(
|
||||||
|
|||||||
Reference in New Issue
Block a user