add HTTP /y/data/common-tables

This commit is contained in:
Martin Michelsen
2024-02-26 20:07:28 -08:00
parent ac62cc455c
commit 32f056c6eb
4 changed files with 141 additions and 2 deletions
+112
View File
@@ -1,11 +1,123 @@
#include "CommonItemSet.hh"
#include "AFSArchive.hh"
#include "EnemyType.hh"
#include "GSLArchive.hh"
#include "StaticGameData.hh"
using namespace std;
template <typename IntT, size_t Count>
JSON to_json(const parray<IntT, Count>& v) {
auto ret = JSON::list();
for (size_t z = 0; z < Count; z++) {
ret.emplace_back(v[z]);
}
return ret;
}
template <typename IntT, size_t Count>
JSON to_json(const parray<CommonItemSet::Table::Range<IntT>, Count>& v) {
auto ret = JSON::list();
for (size_t z = 0; z < Count; z++) {
ret.emplace_back(to_json(v[z]));
}
return ret;
}
template <typename IntT>
JSON to_json(const CommonItemSet::Table::Range<IntT>& v) {
if (v.min == v.max) {
return JSON(v.min);
} else {
return JSON::list({v.min, v.max});
}
}
template <typename IntT, size_t Count1, size_t Count2>
JSON to_json(const parray<parray<IntT, Count2>, Count1>& v) {
auto ret = JSON::list();
for (size_t z = 0; z < Count1; z++) {
ret.emplace_back(to_json(v[z]));
}
return ret;
}
JSON CommonItemSet::Table::json() const {
JSON enemy_meseta_ranges_json = JSON::dict();
JSON enemy_type_drop_probs_json = JSON::dict();
JSON enemy_item_classes_json = JSON::dict();
for (size_t z = 0; z < 0x64; z++) {
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (Episode episode : episodes) {
JSON enemy_meseta_ranges_episode_json = JSON::dict();
JSON enemy_type_drop_probs_episode_json = JSON::dict();
JSON enemy_item_classes_episode_json = JSON::dict();
for (auto type : enemy_types_for_rare_table_index(episode, z)) {
string type_str = name_for_enum(type);
enemy_meseta_ranges_episode_json.emplace(type_str, to_json(this->enemy_meseta_ranges[z]));
enemy_type_drop_probs_episode_json.emplace(type_str, this->enemy_type_drop_probs[z]);
enemy_item_classes_episode_json.emplace(type_str, this->enemy_item_classes[z]);
}
string name = name_for_episode(episode);
enemy_meseta_ranges_json.emplace(name, std::move(enemy_meseta_ranges_episode_json));
enemy_type_drop_probs_json.emplace(name, std::move(enemy_type_drop_probs_episode_json));
enemy_item_classes_json.emplace(name, std::move(enemy_item_classes_episode_json));
}
}
return JSON::dict({
{"BaseWeaponTypeProbTable", to_json(this->base_weapon_type_prob_table)},
{"SubtypeBaseTable", to_json(this->subtype_base_table)},
{"SubtypeAreaLengthTable", to_json(this->subtype_area_length_table)},
{"GrindProbTable", to_json(this->grind_prob_table)},
{"ArmorShieldTypeIndexProbTable", to_json(this->armor_shield_type_index_prob_table)},
{"ArmorSlotCountProbTable", to_json(this->armor_slot_count_prob_table)},
{"EnemyMesetaRanges", std::move(enemy_meseta_ranges_json)},
{"EnemyTypeDropProbs", std::move(enemy_type_drop_probs_json)},
{"EnemyItemClasses", std::move(enemy_item_classes_json)},
{"BoxMesetaRanges", to_json(this->box_meseta_ranges)},
{"HasRareBonusValueProbTable", this->has_rare_bonus_value_prob_table},
{"BonusValueProbTable", to_json(this->bonus_value_prob_table)},
{"NonRareBonusProbSpec", to_json(this->nonrare_bonus_prob_spec)},
{"BonusTypeProbTable", to_json(this->bonus_type_prob_table)},
{"SpecialMult", to_json(this->special_mult)},
{"SpecialPercent", to_json(this->special_percent)},
{"ToolClassProbTable", to_json(this->tool_class_prob_table)},
{"TechniqueIndexProbTable", to_json(this->technique_index_prob_table)},
{"TechniqueLevelRanges", to_json(this->technique_level_ranges)},
{"ArmorOrShieldTypeBias", this->armor_or_shield_type_bias},
{"UnitMaxStarsTable", to_json(this->unit_max_stars_table)},
{"BoxItemClassProbTable", to_json(this->box_item_class_prob_table)},
});
}
JSON CommonItemSet::json() const {
auto modes_dict = JSON::dict();
static const array<GameMode, 4> modes = {GameMode::NORMAL, GameMode::BATTLE, GameMode::CHALLENGE, GameMode::SOLO};
for (const auto& mode : modes) {
auto episodes_dict = JSON::dict();
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (const auto& episode : episodes) {
auto difficulty_dict = JSON::dict();
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
auto section_id_dict = JSON::dict();
for (uint8_t section_id = 0; section_id < 10; section_id++) {
try {
auto table = this->get_table(episode, mode, difficulty, section_id);
section_id_dict.emplace(name_for_section_id(section_id), table->json());
} catch (const runtime_error&) {
}
}
difficulty_dict.emplace(token_name_for_difficulty(difficulty), std::move(section_id_dict));
}
episodes_dict.emplace(token_name_for_episode(episode), std::move(difficulty_dict));
}
modes_dict.emplace(name_for_mode(mode), std::move(episodes_dict));
}
return modes_dict;
}
CommonItemSet::Table::Table(const StringReader& r, bool is_big_endian, bool is_v3) {
if (is_big_endian) {
this->parse_itempt_t<true>(r, is_v3);
+3
View File
@@ -2,6 +2,7 @@
#include <array>
#include <phosg/Encoding.hh>
#include <phosg/JSON.hh>
#include "GSLArchive.hh"
#include "PSOEncryption.hh"
@@ -45,6 +46,7 @@ public:
parray<parray<uint8_t, 10>, 7> box_item_class_prob_table;
void print_enemy_table(FILE* stream) const;
JSON json() const;
private:
template <bool IsBigEndian>
@@ -256,6 +258,7 @@ public:
};
std::shared_ptr<const Table> get_table(Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const;
JSON json() const;
protected:
CommonItemSet() = default;
+25 -2
View File
@@ -844,6 +844,16 @@ JSON HTTPServer::generate_ep3_cards_json(bool trial) const {
return index->definitions_json();
}
JSON HTTPServer::generate_common_tables_json() const {
auto [set_v2, set_v3_v4] = call_on_event_thread<pair<shared_ptr<const CommonItemSet>, shared_ptr<const CommonItemSet>>>(this->state->base, [&]() {
return make_pair(this->state->common_item_set_v2, this->state->common_item_set_v3_v4);
});
return JSON::dict({
{"v1_v2", set_v2->json()},
{"v3_v4", set_v3_v4->json()},
});
}
JSON HTTPServer::generate_rare_tables_json() const {
auto sets = call_on_event_thread<unordered_map<string, shared_ptr<const RareItemSet>>>(this->state->base, [&]() {
return this->state->rare_item_sets;
@@ -880,9 +890,10 @@ JSON HTTPServer::generate_rare_table_json(const std::string& table_name) const {
void HTTPServer::handle_request(struct evhttp_request* req) {
shared_ptr<const JSON> ret;
uint32_t serialize_options = 0;
try {
string uri = evhttp_request_get_uri(req);
uint64_t start_time = now();
string uri = evhttp_request_get_uri(req);
try {
std::unordered_multimap<std::string, std::string> query;
size_t query_pos = uri.find('?');
if (query_pos != string::npos) {
@@ -902,6 +913,7 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
auto endpoints_json = JSON::list({
"/y/data/ep3-cards",
"/y/data/ep3-cards-trial",
"/y/data/common-tables",
"/y/data/rare-tables",
"/y/data/rare-tables/<TABLE-NAME>",
"/y/data/config",
@@ -918,6 +930,8 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
ret = make_shared<JSON>(this->generate_ep3_cards_json(false));
} else if (uri == "/y/data/ep3-cards-trial") {
ret = make_shared<JSON>(this->generate_ep3_cards_json(true));
} else if (uri == "/y/data/common-tables") {
ret = make_shared<JSON>(this->generate_common_tables_json());
} else if (uri == "/y/data/rare-tables") {
ret = make_shared<JSON>(this->generate_rare_tables_json());
} else if (!strncmp(uri.c_str(), "/y/data/rare-tables/", 20)) {
@@ -955,13 +969,22 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
return;
}
uint64_t handler_end = now();
unique_ptr<struct evbuffer, void (*)(struct evbuffer*)> out_buffer(evbuffer_new(), evbuffer_free);
string* serialized = new string(ret->serialize(JSON::SerializeOption::ESCAPE_CONTROLS_ONLY | serialize_options));
size_t size = serialized->size();
uint64_t serialize_end = now();
auto cleanup = +[](const void*, size_t, void* s) -> void {
delete reinterpret_cast<string*>(s);
};
evbuffer_add_reference(out_buffer.get(), serialized->data(), serialized->size(), cleanup, serialized);
this->send_response(req, 200, "application/json", out_buffer.get());
string handler_time = format_duration(handler_end - start_time);
string serialize_time = format_duration(serialize_end - handler_end);
string size_str = format_size(size);
server_log.info("[HTTPServer] %s in [handler: %s, serialize: %s, size: %s]",
uri.c_str(), handler_time.c_str(), serialize_time.c_str(), size_str.c_str());
}
void HTTPServer::thread_fn() {
+1
View File
@@ -70,6 +70,7 @@ protected:
JSON generate_all_json() const;
JSON generate_ep3_cards_json(bool trial) const;
JSON generate_common_tables_json() const;
JSON generate_rare_tables_json() const;
JSON generate_rare_table_json(const std::string& table_name) const;
};