allow server item tables to be enabled by default

This commit is contained in:
Martin Michelsen
2023-10-25 18:48:22 -07:00
parent 6466eec106
commit 7476eb62d3
12 changed files with 201 additions and 86 deletions
+57 -38
View File
@@ -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}},
-1
View File
@@ -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;
-1
View File
@@ -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;
+12
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
-3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+13 -4
View File
@@ -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
+3
View File
@@ -10,6 +10,9 @@
"ServerName": "Alexandria",
"CatchHandlerExceptions": false,
"ItemDropMode": "OnByDefault",
"UseServerItemTables": "OffByDefault",
"LocalAddress": "en0",
"ExternalAddress": "en0",