prevent players from joining game when quest menu is open

This commit is contained in:
Martin Michelsen
2024-05-19 09:05:16 -07:00
parent d294dbcc55
commit 443a0a3037
5 changed files with 61 additions and 41 deletions
+4 -7
View File
@@ -2105,14 +2105,11 @@ struct S_QuestMenuEntry_BB_A2_A4 {
// A9 (C->S): Quest menu closed (canceled)
// Internal name: SndQuestEnd
// No arguments
// This command is sent when the in-game quest menu (A2) is closed. When the
// This command is sent when the in-game quest menu (A2) is closed. This is used
// by the server to unlock the game if the players don't select a quest, since
// players are forbidden from joining while the quest menu is open. When the
// download quest menu is closed, either by downloading a quest or canceling,
// the client sends A0 instead. The existence of the A0 response on the download
// case makes sense, because the client may not be in a lobby and the server may
// need to send another menu or redirect the client. But for the online quest
// menu, the client is already in a game and can move normally after canceling
// the quest menu, so it's not obvious why A9 is needed at all. newserv (and
// probably all other private servers) ignores it.
// the client sends A0 instead.
// Curiously, PSO GC sends uninitialized data in header.flag.
// AA (C->S): Send quest statistic (V3/BB)
+2
View File
@@ -567,6 +567,7 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
ret.emplace("Name", l->name);
ret.emplace("RandomSeed", l->random_seed);
if (l->episode != Episode::EP3) {
ret.emplace("QuestSelectionInProgress", l->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS));
ret.emplace("QuestInProgress", l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS));
ret.emplace("JoinableQuestInProgress", l->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS));
auto variations_json = JSON::list();
@@ -846,6 +847,7 @@ JSON HTTPServer::generate_summary_json() const {
game_json.emplace("MapNumber", (ep3s && ep3s->last_chosen_map) ? ep3s->last_chosen_map->map_number : JSON(nullptr));
game_json.emplace("Rules", (ep3s && ep3s->map_and_rules) ? ep3s->map_and_rules->rules.json() : nullptr);
} else {
game_json.emplace("QuestSelectionInProgress", l->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS));
game_json.emplace("QuestInProgress", l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS));
game_json.emplace("JoinableQuestInProgress", l->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS));
game_json.emplace("SectionID", name_for_section_id(l->effective_section_id()));
+6 -1
View File
@@ -798,6 +798,9 @@ Lobby::JoinError Lobby::join_error_for_client(std::shared_ptr<Client> c, const s
return JoinError::VERSION_CONFLICT;
}
if (this->is_game()) {
if (this->check_flag(Flag::QUEST_SELECTION_IN_PROGRESS)) {
return JoinError::QUEST_SELECTION_IN_PROGRESS;
}
if (this->check_flag(Flag::QUEST_IN_PROGRESS)) {
return JoinError::QUEST_IN_PROGRESS;
}
@@ -973,7 +976,9 @@ bool Lobby::compare_shared(const shared_ptr<const Lobby>& a, const shared_ptr<co
// 5. Difficulty: Normal < Hard < Very Hard < Ultimate
// 6. Game name
static auto get_priority = +[](const shared_ptr<const Lobby>& l) -> size_t {
if (l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS) || l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS)) {
if (l->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS) ||
l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS) ||
l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS)) {
return 4;
}
size_t num_clients = l->count_clients();
+11 -9
View File
@@ -67,15 +67,16 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
PERSISTENT = 0x00000002,
// Flags used only for games
CHEATS_ENABLED = 0x00000100,
QUEST_IN_PROGRESS = 0x00000200,
BATTLE_IN_PROGRESS = 0x00000400,
JOINABLE_QUEST_IN_PROGRESS = 0x00000800,
IS_CLIENT_CUSTOMIZATION = 0x00001000,
IS_SPECTATOR_TEAM = 0x00002000, // episode must be EP3 also
SPECTATORS_FORBIDDEN = 0x00004000,
START_BATTLE_PLAYER_IMMEDIATELY = 0x00008000,
CANNOT_CHANGE_CHEAT_MODE = 0x00010000,
USE_CREATOR_SECTION_ID = 0x00020000,
QUEST_SELECTION_IN_PROGRESS = 0x00000200,
QUEST_IN_PROGRESS = 0x00000400,
BATTLE_IN_PROGRESS = 0x00000800,
JOINABLE_QUEST_IN_PROGRESS = 0x00001000,
IS_CLIENT_CUSTOMIZATION = 0x00002000,
IS_SPECTATOR_TEAM = 0x00004000, // .episode must be EP3 also
SPECTATORS_FORBIDDEN = 0x00008000,
START_BATTLE_PLAYER_IMMEDIATELY = 0x00010000,
CANNOT_CHANGE_CHEAT_MODE = 0x00020000,
USE_CREATOR_SECTION_ID = 0x00040000,
// Flags used only for lobbies
PUBLIC = 0x01000000,
DEFAULT = 0x02000000,
@@ -282,6 +283,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
ALLOWED = 0,
FULL,
VERSION_CONFLICT,
QUEST_SELECTION_IN_PROGRESS,
QUEST_IN_PROGRESS,
BATTLE_IN_PROGRESS,
LOADING,
+38 -24
View File
@@ -1840,6 +1840,8 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
info += "$C6Quest in progress\n";
} else if (game->check_flag(Lobby::Flag::QUEST_IN_PROGRESS)) {
info += "$C4Quest in progress\n";
} else if (game->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS)) {
info += "$C4Selecting quest\n";
}
switch (game->drop_mode) {
@@ -2024,6 +2026,7 @@ void set_lobby_quest(shared_ptr<Lobby> l, shared_ptr<const Quest> q, bool substi
} else {
l->set_flag(Lobby::Flag::QUEST_IN_PROGRESS);
}
l->clear_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS);
l->clear_flag(Lobby::Flag::PERSISTENT);
l->quest = q;
@@ -2440,6 +2443,9 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
case Lobby::JoinError::VERSION_CONFLICT:
send_lobby_message_box(c, "$C7You cannot join this\ngame because it is\nfor a different\nversion of PSO.");
break;
case Lobby::JoinError::QUEST_SELECTION_IN_PROGRESS:
send_lobby_message_box(c, "$C7You cannot join this\ngame because the\nplayers are currently\nchoosing a quest.");
break;
case Lobby::JoinError::QUEST_IN_PROGRESS:
send_lobby_message_box(c, "$C7You cannot join this\ngame because a\nquest is already\nin progress.");
break;
@@ -2843,33 +2849,41 @@ static void on_A2(shared_ptr<Client> c, uint16_t, uint32_t flag, string& data) {
return;
}
// In Episode 3, there are no quest categories, so skip directly to the quest
// filter menu.
if (is_ep3(c->version())) {
send_lobby_message_box(c, "$C7Episode 3 does not\nprovide online quests\nvia this interface.");
return;
}
QuestMenuType menu_type;
if ((c->version() == Version::BB_V4) && flag) {
menu_type = QuestMenuType::GOVERNMENT;
} else {
QuestMenuType menu_type;
if ((c->version() == Version::BB_V4) && flag) {
menu_type = QuestMenuType::GOVERNMENT;
} else {
switch (l->mode) {
case GameMode::NORMAL:
menu_type = QuestMenuType::NORMAL;
break;
case GameMode::BATTLE:
menu_type = QuestMenuType::BATTLE;
break;
case GameMode::CHALLENGE:
menu_type = QuestMenuType::CHALLENGE;
break;
case GameMode::SOLO:
menu_type = QuestMenuType::SOLO;
break;
default:
throw logic_error("invalid game mode");
}
switch (l->mode) {
case GameMode::NORMAL:
menu_type = QuestMenuType::NORMAL;
break;
case GameMode::BATTLE:
menu_type = QuestMenuType::BATTLE;
break;
case GameMode::CHALLENGE:
menu_type = QuestMenuType::CHALLENGE;
break;
case GameMode::SOLO:
menu_type = QuestMenuType::SOLO;
break;
default:
throw logic_error("invalid game mode");
}
send_quest_categories_menu(c, s->quest_index(c->version()), menu_type, l->episode);
}
send_quest_categories_menu(c, s->quest_index(c->version()), menu_type, l->episode);
l->set_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS);
}
static void on_A9(shared_ptr<Client> c, uint16_t, uint32_t, string&) {
auto l = c->require_lobby();
if (l->is_game() && (c->lobby_client_id == l->leader_id)) {
l->clear_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS);
}
}
@@ -5467,7 +5481,7 @@ static on_command_t handlers[0x100][NUM_NON_PATCH_VERSIONS] = {
/* A6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, nullptr},
/* A7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, nullptr},
/* A8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* A9 */ {on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored},
/* A9 */ {on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9},
/* AA */ {nullptr, nullptr, nullptr, nullptr, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA},
/* AB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* AC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB},