implement server drop tables

This commit is contained in:
Martin Michelsen
2023-10-16 23:10:13 -07:00
parent d66c1f5de9
commit 08a1bf3238
13 changed files with 9132 additions and 42 deletions
+16
View File
@@ -1236,6 +1236,21 @@ static void server_command_drop(shared_ptr<Client> c, const std::u16string&) {
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::u16string&) {
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");
} else if (l->item_creator) {
l->item_creator.reset();
send_text_message_printf(l, "Game switched to\nclient rare tables");
} else {
l->create_item_creator();
send_text_message_printf(l, "Game switched to\nserver rare tables");
}
}
static void server_command_item(shared_ptr<Client> c, const std::u16string& args) {
auto s = c->require_server_state();
auto l = c->require_lobby();
@@ -1566,6 +1581,7 @@ static const unordered_map<u16string, ChatCommandDefinition> chat_commands({
{u"$persist", {server_command_persist, nullptr}},
{u"$playrec", {server_command_playrec, nullptr}},
{u"$rand", {server_command_rand, proxy_command_rand}},
{u"$raretable", {server_command_raretable, nullptr}},
{u"$saverec", {server_command_saverec, nullptr}},
{u"$sc", {server_command_send_client, proxy_command_send_client}},
{u"$secid", {server_command_secid, proxy_command_secid}},
+1
View File
@@ -87,6 +87,7 @@ 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,6 +172,7 @@ 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;
+27
View File
@@ -43,6 +43,33 @@ shared_ptr<ServerState> Lobby::require_server_state() const {
return s;
}
void Lobby::create_item_creator() {
auto s = this->require_server_state();
shared_ptr<const RareItemSet> rare_item_set;
if (this->base_version == GameVersion::BB) {
rare_item_set = s->rare_item_sets.at("default-v4");
} else if (this->base_version == GameVersion::GC || this->base_version == GameVersion::XB) {
rare_item_set = s->rare_item_sets.at("default-v3");
} else {
// TODO: SHould there be a separate table for V1 eventually?
rare_item_set = s->rare_item_sets.at("default-v2");
}
this->item_creator.reset(new ItemCreator(
s->common_item_set,
rare_item_set,
s->armor_random_set,
s->tool_random_set,
s->weapon_random_sets.at(this->difficulty),
s->tekker_adjustment_set,
s->item_parameter_table,
this->episode,
(this->mode == GameMode::SOLO) ? GameMode::NORMAL : this->mode,
this->difficulty,
this->section_id,
this->random_seed));
}
void Lobby::create_ep3_server() {
auto s = this->require_server_state();
if (!this->ep3_server) {
+2 -1
View File
@@ -18,7 +18,6 @@
#include "Map.hh"
#include "Player.hh"
#include "Quest.hh"
#include "RareItemSet.hh"
#include "StaticGameData.hh"
#include "Text.hh"
@@ -40,6 +39,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
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
// Flags used only for lobbies
PUBLIC = 0x01000000,
@@ -124,6 +124,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
Lobby& operator=(Lobby&&) = delete;
std::shared_ptr<ServerState> require_server_state() const;
void create_item_creator();
void create_ep3_server();
inline bool is_game() const {
+3 -15
View File
@@ -3349,21 +3349,9 @@ shared_ptr<Lobby> create_game_generic(
game->battle_player = battle_player;
battle_player->set_lobby(game);
}
if (game->base_version == GameVersion::BB) {
if ((game->base_version == GameVersion::BB) || (c->use_server_rare_tables)) {
// TODO: Use appropriate restrictions here if in battle mode
game->item_creator.reset(new ItemCreator(
s->common_item_set,
s->rare_item_set,
s->armor_random_set,
s->tool_random_set,
s->weapon_random_sets.at(game->difficulty),
s->tekker_adjustment_set,
s->item_parameter_table,
game->episode,
(game->mode == GameMode::SOLO) ? GameMode::NORMAL : game->mode,
game->difficulty,
game->section_id,
game->random_seed));
game->create_item_creator();
}
game->event = Lobby::game_event_for_lobby_event(current_lobby->event);
game->block = 0xFF;
@@ -3461,7 +3449,7 @@ static void on_0C_C1_E7_EC(shared_ptr<Client> c, uint16_t command, uint32_t, con
const auto& cmd = check_size_t<C_CreateGame_DCNTE<char>>(data);
u16string name = decode_sjis(cmd.name);
u16string password = decode_sjis(cmd.password);
game = create_game_generic(s, c, name, password);
game = create_game_generic(s, c, name, password, Episode::EP1, GameMode::NORMAL, 0, 0, true);
} else {
const auto& cmd = check_size_t<C_CreateGame_DC_V3_0C_C1_Ep3_EC>(data);
+11 -16
View File
@@ -1185,9 +1185,9 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
return;
}
// If the game is not BB, forward the request to the leader (if drops are
// enabled, or just ignore it) instead of generating the item drop command
if (l->base_version != GameVersion::BB) {
// 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) {
if (l->flags & Lobby::Flag::DROPS_ENABLED) {
forward_subcommand(c, command, flag, data, size);
}
@@ -1208,10 +1208,6 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
cmd.ignore_def = true;
}
if (!l->item_creator.get()) {
throw runtime_error("received box drop subcommand without item creator present");
}
ItemData item;
if (cmd.rt_index == 0x30) {
if (cmd.ignore_def) {
@@ -1220,16 +1216,15 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
item = l->item_creator->on_specialized_box_item_drop(cmd.def[0], cmd.def[1], cmd.def[2]);
}
} else {
if (!l->map) {
throw runtime_error("game does not have a map loaded");
if (l->map) {
const auto& enemy = l->map->enemies.at(cmd.entity_id);
uint32_t expected_rt_index = rare_table_index_for_enemy_type(enemy.type);
if (cmd.rt_index != expected_rt_index) {
c->log.warning("rt_index %02hhX from command does not match entity\'s expected index %02" PRIX32,
cmd.rt_index, expected_rt_index);
}
}
const auto& enemy = l->map->enemies.at(cmd.entity_id);
uint32_t expected_rt_index = rare_table_index_for_enemy_type(enemy.type);
if (cmd.rt_index != expected_rt_index) {
c->log.warning("rt_index %02hhX from command does not match entity\'s expected index %02" PRIX32,
cmd.rt_index, expected_rt_index);
}
item = l->item_creator->on_monster_item_drop(expected_rt_index, cmd.area);
item = l->item_creator->on_monster_item_drop(cmd.rt_index, cmd.area);
}
item.id = l->generate_item_id(0xFF);
+35 -9
View File
@@ -861,15 +861,41 @@ void ServerState::load_level_table() {
}
void ServerState::load_item_tables() {
try {
config_log.info("Loading JSON rare item table");
auto json = JSON::parse(load_file("system/blueburst/rare-table.json"));
this->rare_item_set.reset(new JSONRareItemSet(json));
} catch (const exception& e) {
config_log.info("Failed to load JSON rare item table: %s", e.what());
config_log.info("Loading REL rare item table");
this->rare_item_set.reset(new RELRareItemSet(
this->load_bb_file("ItemRT.rel")));
config_log.info("Loading rare item sets");
for (const auto& filename : list_directory_sorted("system/rare-tables")) {
string path = "system/rare-tables/" + filename;
size_t ext_offset = filename.rfind('.');
string basename = (ext_offset == string::npos) ? filename : filename.substr(0, ext_offset);
if (ends_with(filename, ".json")) {
config_log.info("Loading JSON rare item table %s", filename.c_str());
this->rare_item_sets.emplace(basename, new JSONRareItemSet(JSON::parse(load_file(path))));
} else if (ends_with(filename, ".afs")) {
config_log.info("Loading AFS rare item table %s", filename.c_str());
shared_ptr<string> data(new string(load_file(path)));
this->rare_item_sets.emplace(basename, new AFSRareItemSet(data));
} else if (ends_with(filename, ".gsl")) {
config_log.info("Loading GSL rare item table %s", filename.c_str());
shared_ptr<string> data(new string(load_file(path)));
this->rare_item_sets.emplace(basename, new GSLRareItemSet(data, false));
} else if (ends_with(filename, ".gslb")) {
config_log.info("Loading GSL rare item table %s", filename.c_str());
shared_ptr<string> data(new string(load_file(path)));
this->rare_item_sets.emplace(basename, new GSLRareItemSet(data, true));
} else if (ends_with(filename, ".reg")) {
config_log.info("Loading REL rare item table %s", filename.c_str());
shared_ptr<string> data(new string(load_file(path)));
this->rare_item_sets.emplace(basename, new RELRareItemSet(data));
}
}
if (!this->rare_item_sets.count("default-v4")) {
config_log.info("default-v4 rare item set is not available; loading from BB data");
this->rare_item_sets.emplace("default-v4", new RELRareItemSet(this->load_bb_file("ItemRT.rel")));
}
// Note: These files don't exist in BB, so we use the GC versions of them
+1 -1
View File
@@ -89,7 +89,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::shared_ptr<const LevelTable> level_table;
std::shared_ptr<const BattleParamsIndex> battle_params;
std::shared_ptr<const GSLArchive> bb_data_gsl;
std::shared_ptr<const RareItemSet> rare_item_set;
std::unordered_map<std::string, std::shared_ptr<const RareItemSet>> rare_item_sets;
std::shared_ptr<const CommonItemSet> common_item_set;
std::shared_ptr<const ArmorRandomSet> armor_random_set;
std::shared_ptr<const ToolRandomSet> tool_random_set;