allow server item tables to be enabled by default
This commit is contained in:
+57
-38
@@ -70,11 +70,14 @@ static void check_is_ep3(shared_ptr<Client> c, bool is_ep3) {
|
||||
}
|
||||
}
|
||||
|
||||
static void check_cheats_enabled(shared_ptr<ServerState> s, shared_ptr<Lobby> l = nullptr) {
|
||||
if (s->cheat_mode_behavior == ServerState::CheatModeBehavior::OFF) {
|
||||
throw precondition_failed("$C6Cheats are disabled.");
|
||||
static void check_cheats_enabled(shared_ptr<Lobby> l) {
|
||||
if (!(l->flags & Lobby::Flag::CHEATS_ENABLED)) {
|
||||
throw precondition_failed("$C6This command can\nonly be used in\ncheat mode.");
|
||||
}
|
||||
if (l && !(l->flags & Lobby::Flag::CHEATS_ENABLED)) {
|
||||
}
|
||||
|
||||
static void check_proxy_cheats_enabled(shared_ptr<ServerState> s) {
|
||||
if (s->cheat_mode_behavior != ServerState::BehaviorSwitch::OFF) {
|
||||
throw precondition_failed("$C6This command can\nonly be used in\ncheat mode.");
|
||||
}
|
||||
}
|
||||
@@ -97,17 +100,26 @@ static void server_command_lobby_info(shared_ptr<Client> c, const std::string&)
|
||||
|
||||
} else {
|
||||
if (l->is_game()) {
|
||||
lines.emplace_back(string_printf("Game ID: $C6%08X$C7", l->lobby_id));
|
||||
|
||||
if (!l->is_ep3()) {
|
||||
if (l->max_level == 0xFFFFFFFF) {
|
||||
lines.emplace_back(string_printf("Levels: $C6%d+$C7", l->min_level + 1));
|
||||
lines.emplace_back(string_printf("$C6%08X$C7 L$C6%d+$C7", l->lobby_id, l->min_level + 1));
|
||||
} else {
|
||||
lines.emplace_back(string_printf("Levels: $C6%d-%d$C7", l->min_level + 1, l->max_level + 1));
|
||||
lines.emplace_back(string_printf("$C6%08X$C7 L$C6%d-%d$C7", l->lobby_id, l->min_level + 1, l->max_level + 1));
|
||||
}
|
||||
|
||||
lines.emplace_back(string_printf("$C7Section ID: $C6%s$C7", name_for_section_id(l->section_id).c_str()));
|
||||
lines.emplace_back(string_printf("$C7Cheat mode: $C6%s$C7", (l->flags & Lobby::Flag::CHEATS_ENABLED) ? "on" : "off"));
|
||||
|
||||
if (l->flags & Lobby::Flag::DROPS_ENABLED) {
|
||||
if (l->item_creator) {
|
||||
lines.emplace_back("Server item table");
|
||||
} else {
|
||||
lines.emplace_back("Client item table");
|
||||
}
|
||||
} else {
|
||||
lines.emplace_back("No item drops");
|
||||
}
|
||||
if (l->flags & Lobby::Flag::CHEATS_ENABLED) {
|
||||
lines.emplace_back("Cheats enabled");
|
||||
}
|
||||
|
||||
} else {
|
||||
lines.emplace_back(string_printf("$C7State seed: $C6%08X$C7", l->random_seed));
|
||||
@@ -459,14 +471,12 @@ static void server_command_cheat(shared_ptr<Client> c, const std::string&) {
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_is_leader(l, c);
|
||||
|
||||
if (s->cheat_mode_behavior == ServerState::CheatModeBehavior::OFF) {
|
||||
send_text_message(c, "$C6Cheat mode cannot\nbe enabled on this\nserver");
|
||||
return;
|
||||
if (l->flags & Lobby::Flag::CANNOT_CHANGE_CHEAT_MODE) {
|
||||
send_text_message(c, "$C6Cheat mode cannot\nbe changed on this\nserver");
|
||||
} else {
|
||||
l->flags ^= Lobby::Flag::CHEATS_ENABLED;
|
||||
send_text_message_printf(l, "Cheat mode %s", (l->flags & Lobby::Flag::CHEATS_ENABLED) ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
l->flags ^= Lobby::Flag::CHEATS_ENABLED;
|
||||
send_text_message_printf(l, "Cheat mode %s", (l->flags & Lobby::Flag::CHEATS_ENABLED) ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
static void server_command_lobby_event(shared_ptr<Client> c, const std::string& args) {
|
||||
@@ -1016,7 +1026,7 @@ static void server_command_warp(shared_ptr<Client> c, const std::string& args, b
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_cheats_enabled(s, l);
|
||||
check_cheats_enabled(l);
|
||||
|
||||
uint32_t area = stoul(args, nullptr, 0);
|
||||
if (c->area == area) {
|
||||
@@ -1048,7 +1058,7 @@ static void server_command_warpall(shared_ptr<Client> c, const std::string& args
|
||||
|
||||
static void proxy_command_warp(shared_ptr<ProxyServer::LinkedSession> ses, const std::string& args, bool is_warpall) {
|
||||
auto s = ses->require_server_state();
|
||||
check_cheats_enabled(s);
|
||||
check_proxy_cheats_enabled(s);
|
||||
if (!ses->is_in_game) {
|
||||
send_text_message(ses->client_channel, "$C6You must be in a\ngame to use this\ncommand");
|
||||
return;
|
||||
@@ -1073,7 +1083,7 @@ static void server_command_next(shared_ptr<Client> c, const std::string&) {
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_cheats_enabled(s, l);
|
||||
check_cheats_enabled(l);
|
||||
|
||||
size_t limit = area_limit_for_episode(l->episode);
|
||||
if (limit == 0) {
|
||||
@@ -1084,7 +1094,7 @@ static void server_command_next(shared_ptr<Client> c, const std::string&) {
|
||||
|
||||
static void proxy_command_next(shared_ptr<ProxyServer::LinkedSession> ses, const std::string&) {
|
||||
auto s = ses->require_server_state();
|
||||
check_cheats_enabled(s);
|
||||
check_proxy_cheats_enabled(s);
|
||||
if (!ses->is_in_game) {
|
||||
send_text_message(ses->client_channel, "$C6You must be in a\ngame to use this\ncommand");
|
||||
return;
|
||||
@@ -1149,7 +1159,7 @@ static void server_command_infinite_hp(shared_ptr<Client> c, const std::string&)
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_cheats_enabled(s, l);
|
||||
check_cheats_enabled(l);
|
||||
|
||||
c->options.infinite_hp = !c->options.infinite_hp;
|
||||
send_text_message_printf(c, "$C6Infinite HP %s", c->options.infinite_hp ? "enabled" : "disabled");
|
||||
@@ -1157,7 +1167,7 @@ static void server_command_infinite_hp(shared_ptr<Client> c, const std::string&)
|
||||
|
||||
static void proxy_command_infinite_hp(shared_ptr<ProxyServer::LinkedSession> ses, const std::string&) {
|
||||
auto s = ses->require_server_state();
|
||||
check_cheats_enabled(s);
|
||||
check_proxy_cheats_enabled(s);
|
||||
ses->options.infinite_hp = !ses->options.infinite_hp;
|
||||
send_text_message_printf(ses->client_channel, "$C6Infinite HP %s", ses->options.infinite_hp ? "enabled" : "disabled");
|
||||
}
|
||||
@@ -1166,7 +1176,7 @@ static void server_command_infinite_tp(shared_ptr<Client> c, const std::string&)
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_cheats_enabled(s, l);
|
||||
check_cheats_enabled(l);
|
||||
|
||||
c->options.infinite_tp = !c->options.infinite_tp;
|
||||
send_text_message_printf(c, "$C6Infinite TP %s",
|
||||
@@ -1175,7 +1185,7 @@ static void server_command_infinite_tp(shared_ptr<Client> c, const std::string&)
|
||||
|
||||
static void proxy_command_infinite_tp(shared_ptr<ProxyServer::LinkedSession> ses, const std::string&) {
|
||||
auto s = ses->require_server_state();
|
||||
check_cheats_enabled(s);
|
||||
check_proxy_cheats_enabled(s);
|
||||
ses->options.infinite_tp = !ses->options.infinite_tp;
|
||||
send_text_message_printf(ses->client_channel, "$C6Infinite TP %s",
|
||||
ses->options.infinite_tp ? "enabled" : "disabled");
|
||||
@@ -1185,7 +1195,7 @@ static void server_command_switch_assist(shared_ptr<Client> c, const std::string
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_cheats_enabled(s, l);
|
||||
check_cheats_enabled(l);
|
||||
|
||||
c->options.switch_assist = !c->options.switch_assist;
|
||||
send_text_message_printf(c, "$C6Switch assist %s",
|
||||
@@ -1194,7 +1204,7 @@ static void server_command_switch_assist(shared_ptr<Client> c, const std::string
|
||||
|
||||
static void proxy_command_switch_assist(shared_ptr<ProxyServer::LinkedSession> ses, const std::string&) {
|
||||
auto s = ses->require_server_state();
|
||||
check_cheats_enabled(s);
|
||||
check_proxy_cheats_enabled(s);
|
||||
ses->options.switch_assist = !ses->options.switch_assist;
|
||||
send_text_message_printf(ses->client_channel, "$C6Switch assist %s",
|
||||
ses->options.switch_assist ? "enabled" : "disabled");
|
||||
@@ -1204,22 +1214,31 @@ static void server_command_drop(shared_ptr<Client> c, const std::string&) {
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_is_leader(l, c);
|
||||
l->flags ^= Lobby::Flag::DROPS_ENABLED;
|
||||
send_text_message_printf(l, "Drops %s", (l->flags & Lobby::Flag::DROPS_ENABLED) ? "enabled" : "disabled");
|
||||
if (l->flags & Lobby::Flag::CANNOT_CHANGE_DROPS_ENABLED) {
|
||||
send_text_message(c, "Drop mode cannot\nbe changed on this\nserver");
|
||||
} else {
|
||||
l->flags ^= Lobby::Flag::DROPS_ENABLED;
|
||||
send_text_message_printf(l, "Drops %s", (l->flags & Lobby::Flag::DROPS_ENABLED) ? "enabled" : "disabled");
|
||||
}
|
||||
}
|
||||
|
||||
static void server_command_raretable(shared_ptr<Client> c, const std::string&) {
|
||||
static void server_command_itemtable(shared_ptr<Client> c, const std::string&) {
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_is_leader(l, c);
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
send_text_message_printf(c, "Cannot use client\nrare table on BB");
|
||||
if (l->flags & Lobby::Flag::CANNOT_CHANGE_ITEM_TABLE) {
|
||||
send_text_message(c, "Cannot switch item\ntables on this\nserver");
|
||||
} else if (l->base_version == GameVersion::BB) {
|
||||
send_text_message(c, "Cannot use client\nitem table on BB");
|
||||
} else if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
send_text_message(c, "Cannot use server\nitem tables if item\ntracking is off");
|
||||
} else if (l->item_creator) {
|
||||
l->item_creator.reset();
|
||||
send_text_message_printf(l, "Game switched to\nclient rare tables");
|
||||
send_text_message(l, "Game switched to\nclient item tables");
|
||||
} else {
|
||||
l->create_item_creator();
|
||||
send_text_message_printf(l, "Game switched to\nserver rare tables");
|
||||
send_text_message(l, "Game switched to\nserver item tables");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,7 +1246,7 @@ static void server_command_item(shared_ptr<Client> c, const std::string& args) {
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_cheats_enabled(s, l);
|
||||
check_cheats_enabled(l);
|
||||
|
||||
ItemData item(args);
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
@@ -1241,7 +1260,7 @@ static void server_command_item(shared_ptr<Client> c, const std::string& args) {
|
||||
|
||||
static void proxy_command_item(shared_ptr<ProxyServer::LinkedSession> ses, const std::string& args) {
|
||||
auto s = ses->require_server_state();
|
||||
check_cheats_enabled(s);
|
||||
check_proxy_cheats_enabled(s);
|
||||
if (ses->version() == GameVersion::BB) {
|
||||
send_text_message(ses->client_channel, "$C6This command cannot\nbe used on the proxy\nserver in BB games");
|
||||
return;
|
||||
@@ -1380,7 +1399,7 @@ static void server_command_ep3_unset_field_character(shared_ptr<Client> c, const
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_is_ep3(c, true);
|
||||
check_cheats_enabled(s, l);
|
||||
check_cheats_enabled(l);
|
||||
|
||||
if (l->episode != Episode::EP3) {
|
||||
throw logic_error("non-Ep3 client in Ep3 game");
|
||||
@@ -1534,6 +1553,7 @@ static const unordered_map<string, ChatCommandDefinition> chat_commands({
|
||||
{"$inftime", {server_command_ep3_infinite_time, nullptr}},
|
||||
{"$inftp", {server_command_infinite_tp, proxy_command_infinite_tp}},
|
||||
{"$item", {server_command_item, proxy_command_item}},
|
||||
{"$itemtable", {server_command_itemtable, nullptr}},
|
||||
{"$i", {server_command_item, proxy_command_item}},
|
||||
{"$kick", {server_command_kick, nullptr}},
|
||||
{"$li", {server_command_lobby_info, proxy_command_lobby_info}},
|
||||
@@ -1549,7 +1569,6 @@ static const unordered_map<string, ChatCommandDefinition> chat_commands({
|
||||
{"$persist", {server_command_persist, nullptr}},
|
||||
{"$playrec", {server_command_playrec, nullptr}},
|
||||
{"$rand", {server_command_rand, proxy_command_rand}},
|
||||
{"$raretable", {server_command_raretable, nullptr}},
|
||||
{"$saverec", {server_command_saverec, nullptr}},
|
||||
{"$sc", {server_command_send_client, proxy_command_send_client}},
|
||||
{"$secid", {server_command_secid, proxy_command_secid}},
|
||||
|
||||
@@ -87,7 +87,6 @@ Client::Client(
|
||||
card_battle_table_seat_state(0),
|
||||
next_exp_value(0),
|
||||
can_chat(true),
|
||||
use_server_rare_tables(false),
|
||||
pending_bb_save_player_index(0),
|
||||
dol_base_addr(0) {
|
||||
this->last_switch_enabled_command.header.subcommand = 0;
|
||||
|
||||
@@ -172,7 +172,6 @@ struct Client : public std::enable_shared_from_this<Client> {
|
||||
uint32_t next_exp_value; // next EXP value to give
|
||||
G_SwitchStateChanged_6x05 last_switch_enabled_command;
|
||||
bool can_chat;
|
||||
bool use_server_rare_tables;
|
||||
std::string pending_bb_save_username;
|
||||
uint8_t pending_bb_save_player_index;
|
||||
std::deque<std::function<void(uint32_t, uint32_t)>> function_call_response_queue;
|
||||
|
||||
@@ -167,6 +167,9 @@ void LicenseIndex::remove(uint32_t serial_number) {
|
||||
}
|
||||
|
||||
shared_ptr<License> LicenseIndex::verify_v1_v2(uint32_t serial_number, const string& access_key) const {
|
||||
if (serial_number == 0) {
|
||||
throw no_username();
|
||||
}
|
||||
try {
|
||||
auto& license = this->serial_number_to_license.at(serial_number);
|
||||
if (license->access_key.compare(0, 8, access_key) != 0) {
|
||||
@@ -182,6 +185,9 @@ shared_ptr<License> LicenseIndex::verify_v1_v2(uint32_t serial_number, const str
|
||||
}
|
||||
|
||||
shared_ptr<License> LicenseIndex::verify_gc(uint32_t serial_number, const string& access_key) const {
|
||||
if (serial_number == 0) {
|
||||
throw no_username();
|
||||
}
|
||||
try {
|
||||
auto& license = this->serial_number_to_license.at(serial_number);
|
||||
if (license->access_key != access_key) {
|
||||
@@ -197,6 +203,9 @@ shared_ptr<License> LicenseIndex::verify_gc(uint32_t serial_number, const string
|
||||
}
|
||||
|
||||
shared_ptr<License> LicenseIndex::verify_gc(uint32_t serial_number, const string& access_key, const string& password) const {
|
||||
if (serial_number == 0) {
|
||||
throw no_username();
|
||||
}
|
||||
try {
|
||||
auto& license = this->serial_number_to_license.at(serial_number);
|
||||
if (license->access_key != access_key) {
|
||||
@@ -215,6 +224,9 @@ shared_ptr<License> LicenseIndex::verify_gc(uint32_t serial_number, const string
|
||||
}
|
||||
|
||||
shared_ptr<License> LicenseIndex::verify_bb(const string& username, const string& password) const {
|
||||
if (username.empty() || password.empty()) {
|
||||
throw no_username();
|
||||
}
|
||||
try {
|
||||
auto& license = this->bb_username_to_license.at(username);
|
||||
if (license->bb_password != password) {
|
||||
|
||||
+4
-2
@@ -54,16 +54,18 @@ struct License {
|
||||
|
||||
class LicenseIndex {
|
||||
public:
|
||||
class no_username : public std::invalid_argument {
|
||||
public:
|
||||
no_username() : invalid_argument("serial number is zero or username is missing") {}
|
||||
};
|
||||
class incorrect_password : public std::invalid_argument {
|
||||
public:
|
||||
incorrect_password() : invalid_argument("incorrect password") {}
|
||||
};
|
||||
|
||||
class incorrect_access_key : public std::invalid_argument {
|
||||
public:
|
||||
incorrect_access_key() : invalid_argument("incorrect access key") {}
|
||||
};
|
||||
|
||||
class missing_license : public std::invalid_argument {
|
||||
public:
|
||||
missing_license() : invalid_argument("missing license") {}
|
||||
|
||||
+5
-3
@@ -37,9 +37,11 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
IS_SPECTATOR_TEAM = 0x00002000, // episode must be EP3 also
|
||||
SPECTATORS_FORBIDDEN = 0x00004000,
|
||||
START_BATTLE_PLAYER_IMMEDIATELY = 0x00008000,
|
||||
DROPS_ENABLED = 0x00010000, // Does not affect BB
|
||||
IS_EP3_TRIAL = 0x00020000,
|
||||
USE_SERVER_RARE_TABLE = 0x00040000, // Does not affect BB
|
||||
IS_EP3_TRIAL = 0x00010000,
|
||||
DROPS_ENABLED = 0x00020000,
|
||||
CANNOT_CHANGE_DROPS_ENABLED = 0x00040000,
|
||||
CANNOT_CHANGE_ITEM_TABLE = 0x00080000,
|
||||
CANNOT_CHANGE_CHEAT_MODE = 0x00100000,
|
||||
|
||||
// Flags used only for lobbies
|
||||
PUBLIC = 0x01000000,
|
||||
|
||||
+70
-14
@@ -50,7 +50,7 @@ static shared_ptr<const Menu> proxy_options_menu_for_client(shared_ptr<const Cli
|
||||
"Player notifs", "Show a message\nwhen other players\njoin or leave");
|
||||
add_option(ProxyOptionsMenuItemID::BLOCK_PINGS, c->options.suppress_client_pings,
|
||||
"Block pings", "Block ping commands\nsent by the client");
|
||||
if (s->cheat_mode_behavior != ServerState::CheatModeBehavior::OFF) {
|
||||
if (s->cheat_mode_behavior != ServerState::BehaviorSwitch::OFF) {
|
||||
if (!(c->flags & Client::Flag::IS_EPISODE_3)) {
|
||||
add_option(ProxyOptionsMenuItemID::INFINITE_HP, c->options.infinite_hp,
|
||||
"Infinite HP", "Enable automatic HP\nrestoration when\nyou are hit by an\nenemy or trap\n\nCannot revive you\nfrom one-hit kills");
|
||||
@@ -359,6 +359,11 @@ static void on_DB_V3(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
c->set_license(l);
|
||||
send_command(c, 0x9A, 0x02);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_command(c, 0x9A, 0x03);
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_access_key& e) {
|
||||
send_command(c, 0x9A, 0x03);
|
||||
c->should_disconnect = true;
|
||||
@@ -401,6 +406,11 @@ static void on_88_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
c->set_license(l);
|
||||
send_command(c, 0x88, 0x00);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_message_box(c, "Incorrect serial number");
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_access_key& e) {
|
||||
send_message_box(c, "Incorrect access key");
|
||||
c->should_disconnect = true;
|
||||
@@ -436,6 +446,11 @@ static void on_8B_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
shared_ptr<License> l = s->license_index->verify_v1_v2(serial_number, cmd.access_key.decode());
|
||||
c->set_license(l);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_message_box(c, "Incorrect serial number");
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_access_key& e) {
|
||||
send_message_box(c, "Incorrect access key");
|
||||
c->should_disconnect = true;
|
||||
@@ -482,6 +497,11 @@ static void on_90_DC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
c->set_license(l);
|
||||
send_command(c, 0x90, 0x02);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_command(c, 0x90, 0x03);
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_access_key& e) {
|
||||
send_command(c, 0x90, 0x03);
|
||||
c->should_disconnect = true;
|
||||
@@ -525,6 +545,11 @@ static void on_93_DC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
shared_ptr<License> l = s->license_index->verify_v1_v2(serial_number, cmd.access_key.decode());
|
||||
c->set_license(l);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_message_box(c, "Incorrect serial number");
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_access_key& e) {
|
||||
send_message_box(c, "Incorrect access key");
|
||||
c->should_disconnect = true;
|
||||
@@ -595,6 +620,11 @@ static void on_9A(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
c->set_license(l);
|
||||
send_command(c, 0x9A, 0x02);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_command(c, 0x9A, 0x03);
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_access_key& e) {
|
||||
send_command(c, 0x9A, 0x03);
|
||||
c->should_disconnect = true;
|
||||
@@ -656,6 +686,11 @@ static void on_9C(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
c->set_license(l);
|
||||
send_command(c, 0x9C, 0x01);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_message_box(c, "Incorrect serial number");
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_password& e) {
|
||||
send_command(c, 0x9C, 0x00);
|
||||
c->should_disconnect = true;
|
||||
@@ -774,6 +809,11 @@ static void on_9D_9E(shared_ptr<Client> c, uint16_t command, uint32_t, string& d
|
||||
}
|
||||
c->set_license(l);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_command(c, 0x04, 0x03);
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_access_key& e) {
|
||||
send_command(c, 0x04, 0x03);
|
||||
c->should_disconnect = true;
|
||||
@@ -830,14 +870,19 @@ static void on_93_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
auto l = s->license_index->verify_bb(cmd.username.decode(), cmd.password.decode());
|
||||
c->set_license(l);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
send_message_box(c, "Username is missing");
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::incorrect_password& e) {
|
||||
send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
send_message_box(c, "Incorrect login password");
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::missing_license& e) {
|
||||
if (!s->allow_unregistered_users) {
|
||||
send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
send_message_box(c, "You are not registered on this server");
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
} else {
|
||||
@@ -3336,18 +3381,29 @@ shared_ptr<Lobby> create_game_generic(
|
||||
|
||||
// Only disable drops if the config flag is set and are playing regular
|
||||
// multi-mode. Drops are still enabled for battle and challenge modes.
|
||||
bool drops_enabled = (s->drops_enabled || (mode != GameMode::NORMAL));
|
||||
bool drops_enabled = s->behavior_enabled(s->enable_drops_behavior) || (mode != GameMode::NORMAL);
|
||||
bool use_server_item_table = item_tracking_enabled && s->behavior_enabled(s->use_server_item_tables_behavior);
|
||||
bool cheat_mode_enabled = s->behavior_enabled(s->cheat_mode_behavior);
|
||||
|
||||
bool is_ep3_trial = (c->version() == GameVersion::GC) && (c->flags & Client::Flag::IS_EPISODE_3) && (c->flags & Client::Flag::IS_EP3_TRIAL_EDITION);
|
||||
bool cannot_change_cheat_mode = !s->behavior_can_be_overridden(s->cheat_mode_behavior);
|
||||
bool cannot_change_item_table = !item_tracking_enabled || !s->behavior_can_be_overridden(s->use_server_item_tables_behavior);
|
||||
bool cannot_change_drops_enabled = !s->behavior_can_be_overridden(s->enable_drops_behavior);
|
||||
|
||||
bool is_ep3_trial = (c->version() == GameVersion::GC) &&
|
||||
(c->flags & Client::Flag::IS_EPISODE_3) &&
|
||||
(c->flags & Client::Flag::IS_EP3_TRIAL_EDITION);
|
||||
|
||||
shared_ptr<Lobby> game = s->create_lobby();
|
||||
game->name = name;
|
||||
game->flags = flags |
|
||||
Lobby::Flag::GAME |
|
||||
(is_ep3_trial ? Lobby::Flag::IS_EP3_TRIAL : 0) |
|
||||
(item_tracking_enabled ? Lobby::Flag::ITEM_TRACKING_ENABLED : 0) |
|
||||
(drops_enabled ? Lobby::Flag::DROPS_ENABLED : 0) |
|
||||
(is_ep3_trial ? Lobby::Flag::IS_EP3_TRIAL : 0) |
|
||||
((s->cheat_mode_behavior == ServerState::CheatModeBehavior::ON_BY_DEFAULT) ? Lobby::Flag::CHEATS_ENABLED : 0);
|
||||
(cheat_mode_enabled ? Lobby::Flag::CHEATS_ENABLED : 0) |
|
||||
(cannot_change_drops_enabled ? Lobby::Flag::CANNOT_CHANGE_DROPS_ENABLED : 0) |
|
||||
(cannot_change_item_table ? Lobby::Flag::CANNOT_CHANGE_ITEM_TABLE : 0) |
|
||||
(cannot_change_cheat_mode ? Lobby::Flag::CANNOT_CHANGE_CHEAT_MODE : 0);
|
||||
game->password = password;
|
||||
|
||||
game->base_version = c->version();
|
||||
@@ -3412,10 +3468,15 @@ shared_ptr<Lobby> create_game_generic(
|
||||
game->battle_player = battle_player;
|
||||
battle_player->set_lobby(game);
|
||||
}
|
||||
if ((game->base_version == GameVersion::BB) || (c->use_server_rare_tables)) {
|
||||
// TODO: Use appropriate restrictions here if in battle mode
|
||||
|
||||
for (size_t x = 0; x < 4; x++) {
|
||||
game->next_item_id[x] = (0x00200000 * x) + 0x00010000;
|
||||
}
|
||||
game->next_game_item_id = 0x00810000;
|
||||
if ((game->base_version == GameVersion::BB) || use_server_item_table) {
|
||||
game->create_item_creator();
|
||||
}
|
||||
|
||||
game->event = Lobby::game_event_for_lobby_event(current_lobby->event);
|
||||
game->block = 0xFF;
|
||||
game->max_clients = (game->flags & Lobby::Flag::IS_SPECTATOR_TEAM) ? 12 : 4;
|
||||
@@ -3436,11 +3497,6 @@ shared_ptr<Lobby> create_game_generic(
|
||||
}
|
||||
|
||||
if (game->base_version == GameVersion::BB) {
|
||||
for (size_t x = 0; x < 4; x++) {
|
||||
game->next_item_id[x] = (0x00200000 * x) + 0x00010000;
|
||||
}
|
||||
game->next_game_item_id = 0x00810000;
|
||||
|
||||
game->map.reset(new Map());
|
||||
for (size_t area = 0; area < 0x10; area++) {
|
||||
c->log.info("[Map/%zu] Using variations %" PRIX32 ", %" PRIX32,
|
||||
|
||||
@@ -1293,9 +1293,6 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
if (!(l->flags & Lobby::Flag::DROPS_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is no item creator (that is, the game is BB or has server rare
|
||||
// tables disabled), then forward the request to the leader
|
||||
if (!l->item_creator) {
|
||||
forward_subcommand(c, command, flag, data, size);
|
||||
return;
|
||||
|
||||
+25
-17
@@ -27,7 +27,8 @@ ServerState::ServerState(const char* config_filename, bool is_replay)
|
||||
allow_dc_pc_games(false),
|
||||
allow_gc_xb_games(true),
|
||||
item_tracking_enabled(true),
|
||||
drops_enabled(true),
|
||||
enable_drops_behavior(BehaviorSwitch::ON_BY_DEFAULT),
|
||||
use_server_item_tables_behavior(BehaviorSwitch::OFF_BY_DEFAULT),
|
||||
ep3_send_function_call_enabled(false),
|
||||
catch_handler_exceptions(true),
|
||||
ep3_infinite_meseta(false),
|
||||
@@ -37,7 +38,7 @@ ServerState::ServerState(const char* config_filename, bool is_replay)
|
||||
ep3_jukebox_is_free(false),
|
||||
ep3_behavior_flags(0),
|
||||
run_shell_behavior(RunShellBehavior::DEFAULT),
|
||||
cheat_mode_behavior(CheatModeBehavior::OFF_BY_DEFAULT),
|
||||
cheat_mode_behavior(BehaviorSwitch::OFF_BY_DEFAULT),
|
||||
ep3_card_auction_points(0),
|
||||
ep3_card_auction_min_size(0),
|
||||
ep3_card_auction_max_size(0),
|
||||
@@ -519,6 +520,25 @@ static vector<PortConfiguration> parse_port_configuration(const JSON& json) {
|
||||
void ServerState::parse_config(const JSON& json, bool is_reload) {
|
||||
config_log.info("Parsing configuration");
|
||||
|
||||
auto parse_behavior_switch = [&](const string& json_key, BehaviorSwitch default_value) -> ServerState::BehaviorSwitch {
|
||||
try {
|
||||
string behavior = json.get_string(json_key);
|
||||
if (behavior == "Off") {
|
||||
return ServerState::BehaviorSwitch::OFF;
|
||||
} else if (behavior == "OffByDefault") {
|
||||
return ServerState::BehaviorSwitch::OFF_BY_DEFAULT;
|
||||
} else if (behavior == "OnByDefault") {
|
||||
return ServerState::BehaviorSwitch::ON_BY_DEFAULT;
|
||||
} else if (behavior == "On") {
|
||||
return ServerState::BehaviorSwitch::ON;
|
||||
} else {
|
||||
throw runtime_error("invalid value for " + json_key);
|
||||
}
|
||||
} catch (const out_of_range&) {
|
||||
return default_value;
|
||||
}
|
||||
};
|
||||
|
||||
this->name = json.at("ServerName").as_string();
|
||||
|
||||
if (!is_reload) {
|
||||
@@ -577,7 +597,9 @@ void ServerState::parse_config(const JSON& json, bool is_reload) {
|
||||
this->ip_stack_debug = json.get_bool("IPStackDebug", this->ip_stack_debug);
|
||||
this->allow_unregistered_users = json.get_bool("AllowUnregisteredUsers", this->allow_unregistered_users);
|
||||
this->item_tracking_enabled = json.get_bool("EnableItemTracking", this->item_tracking_enabled);
|
||||
this->drops_enabled = json.get_bool("EnableDrops", this->drops_enabled);
|
||||
this->enable_drops_behavior = parse_behavior_switch("ItemDropMode", this->enable_drops_behavior);
|
||||
this->use_server_item_tables_behavior = parse_behavior_switch("UseServerItemTables", this->use_server_item_tables_behavior);
|
||||
this->cheat_mode_behavior = parse_behavior_switch("CheatModeBehavior", this->cheat_mode_behavior);
|
||||
this->ep3_send_function_call_enabled = json.get_bool("EnableEpisode3SendFunctionCall", this->ep3_send_function_call_enabled);
|
||||
this->catch_handler_exceptions = json.get_bool("CatchHandlerExceptions", this->catch_handler_exceptions);
|
||||
|
||||
@@ -701,20 +723,6 @@ void ServerState::parse_config(const JSON& json, bool is_reload) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const string& behavior = json.at("CheatModeBehavior").as_string();
|
||||
if (behavior == "Off") {
|
||||
this->cheat_mode_behavior = CheatModeBehavior::OFF;
|
||||
} else if (behavior == "OffByDefault") {
|
||||
this->cheat_mode_behavior = CheatModeBehavior::OFF_BY_DEFAULT;
|
||||
} else if (behavior == "OnByDefault") {
|
||||
this->cheat_mode_behavior = CheatModeBehavior::ON_BY_DEFAULT;
|
||||
} else {
|
||||
throw runtime_error("invalid value for CheatModeBehavior");
|
||||
}
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
this->allow_dc_pc_games = json.get_bool("AllowDCPCGames", this->allow_dc_pc_games);
|
||||
this->allow_gc_xb_games = json.get_bool("AllowGCXBGames", this->allow_gc_xb_games);
|
||||
|
||||
|
||||
+12
-3
@@ -40,12 +40,20 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
ALWAYS,
|
||||
NEVER,
|
||||
};
|
||||
enum class CheatModeBehavior {
|
||||
enum class BehaviorSwitch {
|
||||
OFF = 0,
|
||||
OFF_BY_DEFAULT,
|
||||
ON_BY_DEFAULT,
|
||||
ON,
|
||||
};
|
||||
|
||||
static inline bool behavior_enabled(BehaviorSwitch b) {
|
||||
return (b == BehaviorSwitch::ON_BY_DEFAULT) || (b == BehaviorSwitch::ON);
|
||||
}
|
||||
static inline bool behavior_can_be_overridden(BehaviorSwitch b) {
|
||||
return (b == BehaviorSwitch::OFF_BY_DEFAULT) || (b == BehaviorSwitch::ON_BY_DEFAULT);
|
||||
}
|
||||
|
||||
std::string config_filename;
|
||||
bool is_replay;
|
||||
|
||||
@@ -61,7 +69,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
bool allow_dc_pc_games;
|
||||
bool allow_gc_xb_games;
|
||||
bool item_tracking_enabled;
|
||||
bool drops_enabled;
|
||||
BehaviorSwitch enable_drops_behavior;
|
||||
BehaviorSwitch use_server_item_tables_behavior;
|
||||
bool ep3_send_function_call_enabled;
|
||||
bool catch_handler_exceptions;
|
||||
bool ep3_infinite_meseta;
|
||||
@@ -71,7 +80,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
bool ep3_jukebox_is_free;
|
||||
uint32_t ep3_behavior_flags;
|
||||
RunShellBehavior run_shell_behavior;
|
||||
CheatModeBehavior cheat_mode_behavior;
|
||||
BehaviorSwitch cheat_mode_behavior;
|
||||
std::vector<std::shared_ptr<const PSOBBEncryption::KeyFile>> bb_private_keys;
|
||||
std::shared_ptr<const FunctionCodeIndex> function_code_index;
|
||||
std::shared_ptr<const PatchFileIndex> pc_patch_file_index;
|
||||
|
||||
@@ -549,10 +549,19 @@
|
||||
// tracking is always enabled for them.
|
||||
"EnableItemTracking": true,
|
||||
|
||||
// Enable or disable drops by default in non-BB games (drops are always
|
||||
// enabled in BB games). The leader can toggle drops in each game with the
|
||||
// $drop command.
|
||||
"EnableDrops": true,
|
||||
// These options control the behavior of items dropped from boxes and enemies.
|
||||
// ItemDropMode specifies whether any items drop at all; this setting applies
|
||||
// to all versions. UseServerItemTables specifies whether the dropped items
|
||||
// are generated by the client or by the server; this setting applies to all
|
||||
// versions except BB. For BB, items are always generated by the server.
|
||||
// Server item tables can only be used in non-BB games if item tracking is
|
||||
// also enabled.
|
||||
// Either option can be Off, On, OffByDefault, or OnByDefault. If the
|
||||
// ByDefault values are used, the game leader can enable or disable drops with
|
||||
// the $drop command, and can switch between server and client drop logic with
|
||||
// the $itemtable command.
|
||||
"ItemDropMode": "OnByDefault",
|
||||
"UseServerItemTables": "OffByDefault",
|
||||
|
||||
// Whether to enable certain exception handling. Disabling this causes
|
||||
// newserv to abort when any client causes an exception, which is generally
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
"ServerName": "Alexandria",
|
||||
"CatchHandlerExceptions": false,
|
||||
|
||||
"ItemDropMode": "OnByDefault",
|
||||
"UseServerItemTables": "OffByDefault",
|
||||
|
||||
"LocalAddress": "en0",
|
||||
"ExternalAddress": "en0",
|
||||
|
||||
|
||||
Reference in New Issue
Block a user