track specialized boxes server-side

This commit is contained in:
Martin Michelsen
2023-11-13 22:07:21 -08:00
parent 4b4627d3e5
commit 4fe238a01a
161 changed files with 119 additions and 17 deletions
+1 -1
View File
@@ -4388,7 +4388,7 @@ struct G_StandardDropItemRequest_DC_6x60 {
le_uint16_t entity_id = 0;
le_float x = 0.0f;
le_float z = 0.0f;
le_uint16_t unknown_a1 = 0;
le_uint16_t section = 0;
le_uint16_t ignore_def = 0;
} __packed__;
+21 -6
View File
@@ -25,21 +25,36 @@ string Map::Enemy::str() const {
name_for_enum(this->type), this->flags, this->last_hit_by_client_id);
}
string Map::Object::str() const {
return string_printf("[Map::Object %04hX @%04hX p1=%g (%s) p456=[%08" PRIX32 " %08" PRIX32 " %08" PRIX32 "] floor=%02hhX item_drop_checked=%s]",
this->base_type, this->section, this->param1, (this->param1 <= 0.0f) ? "specialized" : "generic",
this->param4, this->param5, this->param6, this->floor, this->item_drop_checked ? "true" : "false");
}
void Map::clear() {
this->enemies.clear();
this->rare_enemy_indexes.clear();
}
void Map::add_objects_from_map_data(const void* data, size_t size) {
void Map::add_objects_from_map_data(uint8_t floor, const void* data, size_t size) {
size_t entry_count = size / sizeof(ObjectEntry);
if (size != entry_count * sizeof(ObjectEntry)) {
throw runtime_error("data size is not a multiple of entry size");
}
(void)data;
// TODO: Actually track objects, so we can e.g. know what to drop from fixed
// boxes
// const auto* map = reinterpret_cast<const ObjectEntry*>(data);
const auto* objects = reinterpret_cast<const ObjectEntry*>(data);
for (size_t z = 0; z < entry_count; z++) {
this->objects.emplace_back(Object{
.base_type = objects[z].base_type,
.section = objects[z].section,
.param1 = objects[z].param1,
.param4 = objects[z].param4,
.param5 = objects[z].param5,
.param6 = objects[z].param6,
.floor = floor,
.item_drop_checked = false,
});
}
}
bool Map::check_and_log_rare_enemy(bool default_is_rare, uint32_t rare_rate) {
@@ -734,7 +749,7 @@ void Map::add_enemies_and_objects_from_quest_data(
throw runtime_error("quest layout object section size is not a multiple of object entry size");
}
static_game_data_log.info("(Floor %02zX) Adding objects", floor);
this->add_objects_from_map_data(r.pgetv(sections.objects + sizeof(header), header.data_size), header.data_size);
this->add_objects_from_map_data(floor, r.pgetv(sections.objects + sizeof(header), header.data_size), header.data_size);
}
if (sections.enemies != 0xFFFFFFFF) {
+21 -2
View File
@@ -48,7 +48,7 @@ struct Map {
/* 1C */ le_uint32_t x_angle;
/* 20 */ le_uint32_t y_angle;
/* 24 */ le_uint32_t z_angle;
/* 28 */ le_float param1;
/* 28 */ le_float param1; // If <= 0, this is a specialized box, and the specialization is in param4/5/6
/* 2C */ le_float param2;
/* 30 */ le_float param3;
/* 34 */ le_uint32_t param4;
@@ -192,6 +192,21 @@ struct Map {
static const RareEnemyRates NO_RARE_ENEMIES;
static const RareEnemyRates DEFAULT_RARE_ENEMIES;
struct Object {
// TODO: Add more fields in here if we ever care about them. Currently we
// only care about boxes with fixed item drops.
uint16_t base_type;
uint16_t section;
float param1; // If <= 0, this is a specialized box, and the specialization is in param4/5/6
uint32_t param4;
uint32_t param5;
uint32_t param6;
uint8_t floor;
bool item_drop_checked;
std::string str() const;
};
struct Enemy {
enum Flag {
HIT_BY_PLAYER0 = 0x01,
@@ -211,11 +226,14 @@ struct Map {
std::string str() const;
} __attribute__((packed));
std::vector<Object> objects;
std::vector<Enemy> enemies;
std::vector<size_t> rare_enemy_indexes;
void clear();
void add_objects_from_map_data(const void* data, size_t size);
void add_objects_from_map_data(uint8_t floor, const void* data, size_t size);
bool check_and_log_rare_enemy(bool default_is_rare, uint32_t rare_rate);
void add_enemy(uint8_t floor, EnemyType type);
void add_enemy(
@@ -244,6 +262,7 @@ struct Map {
StringReader random_enemy_definitions_r,
uint32_t rare_seed,
const RareEnemyRates& rare_rates = Map::DEFAULT_RARE_ENEMIES);
void add_enemies_and_objects_from_quest_data(
Episode episode,
uint8_t difficulty,
+37 -5
View File
@@ -3742,11 +3742,10 @@ shared_ptr<Lobby> create_game_generic(
game->map->add_enemies_from_map_data(
game->episode, game->difficulty, game->event, floor, map_data->data(), map_data->size());
size_t entries_loaded = game->map->enemies.size() - start_offset;
c->log.info("[Map/%zu:e] Loaded %s (%zu entries)",
floor, filename.c_str(), entries_loaded);
c->log.info("[Map/%zu:e] Loaded %s (%zu entries)", floor, filename.c_str(), entries_loaded);
for (size_t z = start_offset; z < game->map->enemies.size(); z++) {
string e_str = game->map->enemies[z].str();
static_game_data_log.info("(Entry %zX) %s", z, e_str.c_str());
static_game_data_log.info("(E-%zX) %s", z, e_str.c_str());
}
any_map_loaded = true;
break;
@@ -3758,10 +3757,43 @@ shared_ptr<Lobby> create_game_generic(
throw runtime_error(string_printf("no enemy maps loaded for floor %zu", floor));
}
}
auto object_filenames = map_filenames_for_variation(
game->episode,
is_solo,
floor,
game->variations[floor * 2],
game->variations[floor * 2 + 1],
false);
if (object_filenames.empty()) {
c->log.info("[Map/%zu:o] No file to load", floor);
} else {
bool any_map_loaded = false;
for (const string& filename : object_filenames) {
try {
auto map_data = s->load_bb_file(filename, "", "map/" + filename);
size_t start_offset = game->map->objects.size();
game->map->add_objects_from_map_data(floor, map_data->data(), map_data->size());
size_t entries_loaded = game->map->objects.size() - start_offset;
c->log.info("[Map/%zu:o] Loaded %s (%zu entries)", floor, filename.c_str(), entries_loaded);
for (size_t z = start_offset; z < game->map->objects.size(); z++) {
string e_str = game->map->objects[z].str();
static_game_data_log.info("(K-%zX) %s", z, e_str.c_str());
}
any_map_loaded = true;
break;
} catch (const exception& e) {
c->log.info("[Map/%zu:o] Failed to load %s: %s", floor, filename.c_str(), e.what());
}
}
if (!any_map_loaded) {
throw runtime_error(string_printf("no object maps loaded for floor %zu", floor));
}
}
}
c->log.info("Loaded maps contain %zu enemy entries overall (%zu as rares)",
game->map->enemies.size(), game->map->rare_enemy_indexes.size());
c->log.info("Loaded maps contain %zu object entries and %zu enemy entries overall (%zu as rares)",
game->map->objects.size(), game->map->enemies.size(), game->map->rare_enemy_indexes.size());
}
return game;
}
+39 -3
View File
@@ -1436,7 +1436,42 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
ItemData item;
if (cmd.rt_index == 0x30) {
if (cmd.ignore_def) {
if (l->map) {
auto& object = l->map->objects.at(cmd.entity_id);
if (cmd.floor != object.floor) {
l->log.warning("Floor %02hhX from command does not match object\'s expected floor %02hhX",
cmd.floor, object.floor);
}
bool object_ignore_def = (object.param1 > 0.0);
if (cmd.ignore_def != object_ignore_def) {
l->log.warning("ignore_def value %s from command does not match object\'s expected ignore_def %s (from p1=%g)",
cmd.ignore_def ? "true" : "false", object_ignore_def ? "true" : "false", object.param1);
}
if (object.item_drop_checked) {
l->log.warning("Object drop check has already occurred");
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
send_text_message_printf(c, "$C5K-%hX %04hX __CHECKED__", cmd.entity_id.load(), object.base_type);
}
} else if (object_ignore_def) {
l->log.info("Creating item from box %04hX (area %02hX)", cmd.entity_id.load(), cmd.effective_area);
item = l->item_creator->on_box_item_drop(cmd.entity_id, cmd.effective_area);
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
send_text_message_printf(c, "$C5K-%hX %04hX GEN %s", cmd.entity_id.load(), object.base_type, item.empty() ? "EMPTY" : "ITEM");
}
} else {
l->log.info("Creating item from box %04hX (area %02hX; specialized with %08" PRIX32 " %08" PRIX32 " %08" PRIX32 ")",
cmd.entity_id.load(), cmd.effective_area, object.param4, object.param5, object.param6);
item = l->item_creator->on_specialized_box_item_drop(cmd.entity_id, object.param4, object.param5, object.param6);
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
send_text_message_printf(c, "$C5K-%hX %04hX CST %s", cmd.entity_id.load(), object.base_type, item.empty() ? "EMPTY" : "ITEM");
}
}
object.item_drop_checked = true;
} else if (cmd.ignore_def) {
l->log.info("Creating item from box %04hX (area %02hX)", cmd.entity_id.load(), cmd.effective_area);
item = l->item_creator->on_box_item_drop(cmd.entity_id, cmd.effective_area);
} else {
@@ -1444,17 +1479,18 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
cmd.entity_id.load(), cmd.effective_area, cmd.def[0].load(), cmd.def[1].load(), cmd.def[2].load());
item = l->item_creator->on_specialized_box_item_drop(cmd.entity_id, cmd.def[0], cmd.def[1], cmd.def[2]);
}
} else {
l->log.info("Creating item from enemy %04hX (area %02hX)", cmd.entity_id.load(), cmd.effective_area);
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,
l->log.warning("rt_index %02hhX from command does not match entity\'s expected index %02" PRIX32,
cmd.rt_index, expected_rt_index);
}
if (cmd.floor != enemy.floor) {
c->log.warning("Floor %02hhX from command does not match entity\'s expected floor %02hhX",
l->log.warning("Floor %02hhX from command does not match entity\'s expected floor %02hhX",
cmd.floor, enemy.floor);
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More