add ep3 cards and rare tables to HTTP server
This commit is contained in:
@@ -80,6 +80,16 @@ const char* name_for_link_color(uint8_t color) {
|
||||
}
|
||||
}
|
||||
|
||||
JSON json_for_link_colors(const parray<uint8_t, 8>& colors) {
|
||||
JSON ret = JSON::list();
|
||||
for (size_t z = 0; z < colors.size(); z++) {
|
||||
if (colors[z]) {
|
||||
ret.emplace_back(name_for_link_color(colors[z]));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Location::Location() : Location(0, 0) {}
|
||||
Location::Location(uint8_t x, uint8_t y) : Location(x, y, Direction::RIGHT) {}
|
||||
Location::Location(uint8_t x, uint8_t y, Direction direction)
|
||||
@@ -1016,6 +1026,111 @@ Card: %04" PRIX32 " \"%s\"\n\
|
||||
}
|
||||
}
|
||||
|
||||
JSON CardDefinition::Stat::json() const {
|
||||
const char* type_str = "unknown";
|
||||
switch (this->type) {
|
||||
case Type::BLANK:
|
||||
type_str = "BLANK";
|
||||
break;
|
||||
case Type::STAT:
|
||||
type_str = "DEFAULT";
|
||||
break;
|
||||
case Type::PLUS_STAT:
|
||||
type_str = "PLUS";
|
||||
break;
|
||||
case Type::MINUS_STAT:
|
||||
type_str = "MINUS";
|
||||
break;
|
||||
case Type::EQUALS_STAT:
|
||||
type_str = "EQUALS";
|
||||
break;
|
||||
case Type::UNKNOWN:
|
||||
type_str = "UNKNOWN";
|
||||
break;
|
||||
case Type::PLUS_UNKNOWN:
|
||||
type_str = "PLUS_UNKNOWN";
|
||||
break;
|
||||
case Type::MINUS_UNKNOWN:
|
||||
type_str = "MINUS_UNKNOWN";
|
||||
break;
|
||||
case Type::EQUALS_UNKNOWN:
|
||||
type_str = "EQUALS_UNKNOWN";
|
||||
break;
|
||||
}
|
||||
return JSON::dict({
|
||||
{"type", type_str},
|
||||
{"value", this->stat},
|
||||
});
|
||||
}
|
||||
|
||||
JSON CardDefinition::Effect::json() const {
|
||||
return JSON::dict({
|
||||
{"EffectNum", this->effect_num},
|
||||
{"ConditionType", name_for_enum(this->type)},
|
||||
{"Expression", this->expr.decode()},
|
||||
{"When", this->when},
|
||||
{"Arg1", this->arg1.decode()},
|
||||
{"Arg2", this->arg2.decode()},
|
||||
{"Arg3", this->arg3.decode()},
|
||||
{"ApplyCriterion", name_for_enum(this->apply_criterion)},
|
||||
{"NameIndex", this->name_index},
|
||||
});
|
||||
}
|
||||
|
||||
JSON CardDefinition::json() const {
|
||||
JSON range_json;
|
||||
if (this->range[0] == 0x000FFFFF) {
|
||||
range_json = "ENTIRE_FIELD";
|
||||
} else {
|
||||
range_json = JSON::list();
|
||||
for (size_t y = 0; y < 6; y++) {
|
||||
uint32_t row = this->range[y];
|
||||
auto& row_json = range_json.emplace_back(JSON::list());
|
||||
for (size_t x = 0; x < 5; x++) {
|
||||
row_json.emplace_back((row & 0x00010000) ? true : false);
|
||||
row <<= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSON effects_json = JSON::list();
|
||||
for (size_t z = 0; z < this->effects.size(); z++) {
|
||||
if (!this->effects[z].is_empty()) {
|
||||
effects_json.emplace_back(this->effects[z].json());
|
||||
}
|
||||
}
|
||||
|
||||
return JSON::dict({
|
||||
{"CardID", this->card_id.load()},
|
||||
{"JPName", this->jp_name.decode()},
|
||||
{"CardType", name_for_enum(this->type)},
|
||||
{"SelfCost", this->self_cost},
|
||||
{"AllyCost", this->ally_cost},
|
||||
{"HP", this->hp.json()},
|
||||
{"AP", this->ap.json()},
|
||||
{"TP", this->tp.json()},
|
||||
{"MV", this->mv.json()},
|
||||
{"LeftColors", json_for_link_colors(this->left_colors)},
|
||||
{"RightColors", json_for_link_colors(this->right_colors)},
|
||||
{"TopColors", json_for_link_colors(this->top_colors)},
|
||||
{"Range", std::move(range_json)},
|
||||
{"TargetMode", name_for_target_mode(this->target_mode)},
|
||||
{"AssistTurns", this->assist_turns},
|
||||
{"CannotMove", this->cannot_move ? true : false},
|
||||
{"CannotAttack", this->cannot_attack ? true : false},
|
||||
{"CannotDrop", this->cannot_drop ? true : false},
|
||||
{"UsableCriterion", name_for_enum(this->usable_criterion)},
|
||||
{"Rank", name_for_rank(this->rank)},
|
||||
{"CardClass", name_for_enum(this->card_class())},
|
||||
{"AssistAIParams", this->assist_ai_params.load()},
|
||||
{"DropRates", JSON::list({this->drop_rates[0].load(), this->drop_rates[1].load()})},
|
||||
{"ENName", this->en_name.decode()},
|
||||
{"JPShortName", this->jp_short_name.decode()},
|
||||
{"ENShortName", this->en_short_name.decode()},
|
||||
{"Effects", std::move(effects_json)},
|
||||
});
|
||||
}
|
||||
|
||||
void PlayerConfig::decrypt() {
|
||||
if (!this->is_encrypted) {
|
||||
return;
|
||||
@@ -1498,6 +1613,97 @@ void MapDefinition::assert_semantically_equivalent(const MapDefinition& other) c
|
||||
}
|
||||
}
|
||||
|
||||
JSON MapDefinition::CameraSpec::json() const {
|
||||
return JSON::dict({
|
||||
{"Camera", JSON::list({this->camera_x.load(), this->camera_y.load(), this->camera_z.load()})},
|
||||
{"Focus", JSON::list({this->focus_x.load(), this->focus_y.load(), this->focus_z.load()})},
|
||||
});
|
||||
}
|
||||
|
||||
JSON MapDefinition::NPCDeck::json() const {
|
||||
JSON card_ids_json = JSON::list();
|
||||
for (size_t z = 0; z < this->card_ids.size(); z++) {
|
||||
if (this->card_ids[z] != 0xFFFF) {
|
||||
card_ids_json.emplace_back(this->card_ids[z].load());
|
||||
}
|
||||
}
|
||||
return JSON::dict({
|
||||
{"Name", this->name.decode()},
|
||||
{"CardIDs", std::move(card_ids_json)},
|
||||
});
|
||||
}
|
||||
|
||||
JSON MapDefinition::AIParams::json() const {
|
||||
JSON params_json = JSON::list();
|
||||
for (size_t z = 0; z < this->params.size(); z++) {
|
||||
params_json.emplace_back(this->params[z].load());
|
||||
}
|
||||
return JSON::dict({
|
||||
{"IsArkz", this->is_arkz ? true : false},
|
||||
{"Name", this->name.decode()},
|
||||
{"CardIDs", std::move(params_json)},
|
||||
});
|
||||
}
|
||||
|
||||
JSON MapDefinition::DialogueSet::json() const {
|
||||
JSON strings_json = JSON::list();
|
||||
for (size_t z = 0; z < this->strings.size(); z++) {
|
||||
strings_json.emplace_back(this->strings[z].decode());
|
||||
}
|
||||
return JSON::dict({
|
||||
{"When", this->when.load()},
|
||||
{"PercentChance", this->percent_chance.load()},
|
||||
{"CardIDs", std::move(strings_json)},
|
||||
});
|
||||
}
|
||||
|
||||
JSON MapDefinition::EntryState::json() const {
|
||||
JSON player_type_json;
|
||||
switch (this->player_type) {
|
||||
case 0x00:
|
||||
player_type_json = "Player";
|
||||
break;
|
||||
case 0x01:
|
||||
player_type_json = "Player/COM";
|
||||
break;
|
||||
case 0x02:
|
||||
player_type_json = "COM";
|
||||
break;
|
||||
case 0x03:
|
||||
player_type_json = "NPC";
|
||||
break;
|
||||
case 0x04:
|
||||
player_type_json = "NONE";
|
||||
break;
|
||||
case 0xFF:
|
||||
player_type_json = "FREE";
|
||||
break;
|
||||
default:
|
||||
player_type_json = this->player_type;
|
||||
}
|
||||
JSON deck_type_json;
|
||||
switch (this->deck_type) {
|
||||
case 0x00:
|
||||
deck_type_json = "HERO ONLY";
|
||||
break;
|
||||
case 0x01:
|
||||
deck_type_json = "DARK ONLY";
|
||||
break;
|
||||
case 0xFF:
|
||||
deck_type_json = "ANY";
|
||||
break;
|
||||
default:
|
||||
deck_type_json = this->deck_type;
|
||||
}
|
||||
return JSON::dict({
|
||||
{"PlayerType", std::move(player_type_json)},
|
||||
{"DeckType", std::move(deck_type_json)},
|
||||
});
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// JSON MapDefinition::json() const { ... }
|
||||
|
||||
string MapDefinition::CameraSpec::str() const {
|
||||
return string_printf(
|
||||
"CameraSpec[a1=(%g %g %g %g %g %g %g %g %g) camera=(%g %g %g) focus=(%g %g %g) a2=(%g %g %g)]",
|
||||
@@ -2259,6 +2465,14 @@ uint64_t CardIndex::definitions_mtime() const {
|
||||
return this->mtime_for_card_definitions;
|
||||
}
|
||||
|
||||
JSON CardIndex::definitions_json() const {
|
||||
JSON ret = JSON::dict();
|
||||
for (const auto& it : this->card_definitions_by_name) {
|
||||
ret.emplace(it.first, it.second->def.json());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
string CardIndex::normalize_card_name(const string& name) {
|
||||
string ret;
|
||||
for (char ch : name) {
|
||||
|
||||
@@ -468,6 +468,7 @@ struct CardDefinition {
|
||||
|
||||
void decode_code();
|
||||
std::string str() const;
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct Effect {
|
||||
@@ -504,6 +505,7 @@ struct CardDefinition {
|
||||
bool is_empty() const;
|
||||
static std::string str_for_arg(const std::string& arg);
|
||||
std::string str(const char* separator = ", ", const TextSet* text_archive = nullptr) const;
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 0000 */ be_uint32_t card_id;
|
||||
@@ -770,6 +772,7 @@ struct CardDefinition {
|
||||
|
||||
void decode_range();
|
||||
std::string str(bool single_line = true, const TextSet* text_archive = nullptr) const;
|
||||
JSON json() const;
|
||||
} __attribute__((packed)); // 0x128 bytes in total
|
||||
|
||||
struct CardDefinitionsFooter {
|
||||
@@ -1150,6 +1153,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
/* 48 */
|
||||
|
||||
std::string str() const;
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
|
||||
// This array specifies the camera zone maps. A camera zone map is a subset of
|
||||
@@ -1207,6 +1211,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
/* 00 */ pstring<TextEncoding::SJIS, 0x18> name;
|
||||
/* 18 */ parray<be_uint16_t, 0x20> card_ids; // Last one appears to always be FFFF
|
||||
/* 58 */
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
/* 1FE8 */ parray<NPCDeck, 3> npc_decks; // Unused if name[0] == 0
|
||||
|
||||
@@ -1222,6 +1227,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
// TODO: Figure out exactly how these are used and document here.
|
||||
/* 0018 */ parray<be_uint16_t, 0x7E> params;
|
||||
/* 0114 */
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
/* 20F0 */ parray<AIParams, 3> npc_ai_params; // Unused if name[0] == 0
|
||||
|
||||
@@ -1274,6 +1280,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
// strings, excluding any that are empty or begin with the character '^'.
|
||||
/* 0004 */ parray<pstring<TextEncoding::SJIS, 0x40>, 4> strings;
|
||||
/* 0104 */
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
|
||||
// There are up to 0x10 of these per valid NPC, but only the first 13 of them
|
||||
@@ -1356,6 +1363,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
|
||||
bool operator==(const EntryState& other) const = default;
|
||||
bool operator!=(const EntryState& other) const = default;
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
/* 5A10 */ parray<EntryState, 4> entry_states;
|
||||
/* 5A18 */
|
||||
@@ -1371,6 +1379,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
void assert_semantically_equivalent(const MapDefinition& other) const;
|
||||
|
||||
std::string str(const CardIndex* card_index, uint8_t language) const;
|
||||
JSON json() const;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct MapDefinitionTrial {
|
||||
@@ -1453,6 +1462,7 @@ public:
|
||||
std::shared_ptr<const CardEntry> definition_for_name_normalized(const std::string& name) const;
|
||||
std::set<uint32_t> all_ids() const;
|
||||
uint64_t definitions_mtime() const;
|
||||
JSON definitions_json() const;
|
||||
|
||||
private:
|
||||
static std::string normalize_card_name(const std::string& name);
|
||||
|
||||
@@ -815,6 +815,38 @@ JSON HTTPServer::generate_all_json() const {
|
||||
});
|
||||
}
|
||||
|
||||
JSON HTTPServer::generate_ep3_cards_json(bool trial) const {
|
||||
const auto& index = trial ? this->state->ep3_card_index_trial : this->state->ep3_card_index;
|
||||
return index->definitions_json();
|
||||
}
|
||||
|
||||
JSON HTTPServer::generate_rare_tables_json() const {
|
||||
JSON ret = JSON::list();
|
||||
for (const auto& it : this->state->rare_item_sets) {
|
||||
ret.emplace_back(it.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSON HTTPServer::generate_rare_table_json(const std::string& table_name) const {
|
||||
try {
|
||||
const auto& table = this->state->rare_item_sets.at(table_name);
|
||||
shared_ptr<const ItemNameIndex> name_index;
|
||||
if (ends_with(table_name, "-v1")) {
|
||||
name_index = this->state->item_name_index(Version::DC_V1);
|
||||
} else if (ends_with(table_name, "-v2")) {
|
||||
name_index = this->state->item_name_index(Version::PC_V2);
|
||||
} else if (ends_with(table_name, "-v3")) {
|
||||
name_index = this->state->item_name_index(Version::GC_V3);
|
||||
} else if (ends_with(table_name, "-v4")) {
|
||||
name_index = this->state->item_name_index(Version::BB_V4);
|
||||
}
|
||||
return table->json(name_index);
|
||||
} catch (const out_of_range&) {
|
||||
throw http_error(404, "table does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||
JSON ret;
|
||||
uint32_t serialize_options = 0;
|
||||
@@ -835,14 +867,29 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||
|
||||
if (uri == "/") {
|
||||
auto endpoints_json = JSON::list({
|
||||
"/y/data/ep3-cards",
|
||||
"/y/data/ep3-cards-trial",
|
||||
"/y/data/rare-tables",
|
||||
"/y/data/config",
|
||||
"/y/clients",
|
||||
"/y/proxy-clients",
|
||||
"/y/lobbies",
|
||||
"/y/server",
|
||||
"/y/summary",
|
||||
"/y/all",
|
||||
});
|
||||
ret = JSON::dict({{"endpoints", std::move(endpoints_json)}});
|
||||
|
||||
} else if (uri == "/y/data/ep3-cards") {
|
||||
ret = this->generate_ep3_cards_json(false);
|
||||
} else if (uri == "/y/data/ep3-cards-trial") {
|
||||
ret = this->generate_ep3_cards_json(true);
|
||||
} else if (uri == "/y/data/rare-tables") {
|
||||
ret = this->generate_rare_tables_json();
|
||||
} else if (!strncmp(uri.c_str(), "/y/data/rare-tables/", 20)) {
|
||||
ret = this->generate_rare_table_json(uri.substr(20));
|
||||
} else if (uri == "/y/data/config") {
|
||||
ret = this->state->config_json;
|
||||
} else if (uri == "/y/clients") {
|
||||
ret = this->generate_game_server_clients_json();
|
||||
} else if (uri == "/y/proxy-clients") {
|
||||
|
||||
@@ -61,4 +61,8 @@ protected:
|
||||
JSON generate_lobbies_json() const;
|
||||
JSON generate_summary_json() const;
|
||||
JSON generate_all_json() const;
|
||||
|
||||
JSON generate_ep3_cards_json(bool trial) const;
|
||||
JSON generate_rare_tables_json() const;
|
||||
JSON generate_rare_table_json(const std::string& table_name) const;
|
||||
};
|
||||
|
||||
+2
-1
@@ -1649,7 +1649,8 @@ Action a_convert_rare_item_set(
|
||||
if (output_filename.empty() || (output_filename == "-")) {
|
||||
rs->print_all_collections(stdout, s->item_name_index(version));
|
||||
} else if (ends_with(output_filename, ".json")) {
|
||||
string data = rs->serialize_json(s->item_name_index(version));
|
||||
auto json = rs->json(s->item_name_index(version));
|
||||
string data = json.serialize(JSON::SerializeOption::FORMAT | JSON::SerializeOption::HEX_INTEGERS | JSON::SerializeOption::SORT_DICT_KEYS);
|
||||
write_output_data(args, data.data(), data.size(), nullptr);
|
||||
} else if (ends_with(output_filename, ".gsl")) {
|
||||
string data = rs->serialize_gsl(args.get<bool>("big-endian"));
|
||||
|
||||
+2
-2
@@ -427,7 +427,7 @@ std::string RareItemSet::serialize_gsl(bool big_endian) const {
|
||||
return GSLArchive::generate(files, big_endian);
|
||||
}
|
||||
|
||||
std::string RareItemSet::serialize_json(shared_ptr<const ItemNameIndex> name_index) const {
|
||||
JSON RareItemSet::json(shared_ptr<const ItemNameIndex> name_index) 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) {
|
||||
@@ -507,7 +507,7 @@ std::string RareItemSet::serialize_json(shared_ptr<const ItemNameIndex> name_ind
|
||||
modes_dict.emplace(name_for_mode(mode), std::move(episodes_dict));
|
||||
}
|
||||
|
||||
return modes_dict.serialize(JSON::SerializeOption::FORMAT | JSON::SerializeOption::HEX_INTEGERS | JSON::SerializeOption::SORT_DICT_KEYS);
|
||||
return modes_dict;
|
||||
}
|
||||
|
||||
void RareItemSet::print_collection(
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public:
|
||||
|
||||
std::string serialize_afs(bool is_v1) const;
|
||||
std::string serialize_gsl(bool big_endian) const;
|
||||
std::string serialize_json(std::shared_ptr<const ItemNameIndex> name_index = nullptr) const;
|
||||
JSON json(std::shared_ptr<const ItemNameIndex> name_index = nullptr) const;
|
||||
|
||||
void print_collection(
|
||||
FILE* stream,
|
||||
|
||||
Reference in New Issue
Block a user