mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2025-02-11 00:39:50 +00:00
Renamed mod manifest to mod.json, added display_name, description, short_description fields (#125)
This commit is contained in:
parent
38df8e3ddc
commit
b2d07ecd5a
@ -20,11 +20,14 @@
|
||||
|
||||
constexpr std::string_view symbol_filename = "mod_syms.bin";
|
||||
constexpr std::string_view binary_filename = "mod_binary.bin";
|
||||
constexpr std::string_view manifest_filename = "manifest.json";
|
||||
constexpr std::string_view manifest_filename = "mod.json";
|
||||
|
||||
struct ModManifest {
|
||||
std::string mod_id;
|
||||
std::string version_string;
|
||||
std::string display_name;
|
||||
std::string description;
|
||||
std::string short_description;
|
||||
std::vector<std::string> authors;
|
||||
std::string game_id;
|
||||
std::string minimum_recomp_version;
|
||||
@ -162,7 +165,7 @@ static T read_toml_value(const toml::table& data, std::string_view key, bool req
|
||||
|
||||
if (value_node == nullptr) {
|
||||
if (required) {
|
||||
throw toml::parse_error(("Missing required field " + std::string{key}).c_str(), data.source());
|
||||
throw toml::parse_error(("Missing required field \"" + std::string{key} + "\"").c_str(), data.source());
|
||||
}
|
||||
else {
|
||||
return T{};
|
||||
@ -174,7 +177,7 @@ static T read_toml_value(const toml::table& data, std::string_view key, bool req
|
||||
return opt.value();
|
||||
}
|
||||
else {
|
||||
throw toml::parse_error(("Incorrect type for field " + std::string{key}).c_str(), data.source());
|
||||
throw toml::parse_error(("Incorrect type for field \"" + std::string{key} + "\"").c_str(), data.source());
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,6 +223,9 @@ ModManifest parse_mod_config_manifest(const std::filesystem::path& basedir, cons
|
||||
|
||||
// Mod ID
|
||||
ret.mod_id = read_toml_value<std::string_view>(manifest_table, "id", true);
|
||||
if (!N64Recomp::validate_mod_id(ret.mod_id)) {
|
||||
throw toml::parse_error("Invalid mod id", manifest_table["id"].node()->source());
|
||||
}
|
||||
|
||||
// Mod version
|
||||
ret.version_string = read_toml_value<std::string_view>(manifest_table, "version", true);
|
||||
@ -228,6 +234,15 @@ ModManifest parse_mod_config_manifest(const std::filesystem::path& basedir, cons
|
||||
throw toml::parse_error("Invalid mod version", manifest_table["version"].node()->source());
|
||||
}
|
||||
|
||||
// Display name
|
||||
ret.display_name = read_toml_value<std::string_view>(manifest_table, "display_name", true);
|
||||
|
||||
// Description (optional)
|
||||
ret.description = read_toml_value<std::string_view>(manifest_table, "description", false);
|
||||
|
||||
// Short description (optional)
|
||||
ret.short_description = read_toml_value<std::string_view>(manifest_table, "short_description", false);
|
||||
|
||||
// Authors
|
||||
const toml::array& authors_array = read_toml_array(manifest_table, "authors", true);
|
||||
authors_array.for_each([&ret](auto&& el) {
|
||||
@ -426,57 +441,53 @@ bool parse_callback_name(std::string_view data, std::string& dependency_name, st
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_vector_elements(std::ostream& output_file, const std::vector<std::string>& vec, bool compact) {
|
||||
char separator = compact ? ' ' : '\n';
|
||||
for (size_t i = 0; i < vec.size(); i++) {
|
||||
const std::string& val = vec[i];
|
||||
fmt::print(output_file, "{}\"{}\"{}{}",
|
||||
compact ? "" : " ", val, i == vec.size() - 1 ? "" : ",", separator);
|
||||
toml::array string_vector_to_toml(const std::vector<std::string>& input) {
|
||||
toml::array ret{};
|
||||
for (const std::string& str : input) {
|
||||
ret.emplace_back(str);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void write_manifest(const std::filesystem::path& path, const ModManifest& manifest) {
|
||||
std::ofstream output_file(path);
|
||||
toml::table output_data{};
|
||||
|
||||
fmt::print(output_file,
|
||||
"{{\n"
|
||||
" \"game_id\": \"{}\",\n"
|
||||
" \"id\": \"{}\",\n"
|
||||
" \"version\": \"{}\",\n"
|
||||
" \"authors\": [\n",
|
||||
manifest.game_id, manifest.mod_id, manifest.version_string);
|
||||
output_data.emplace("game_id", manifest.game_id);
|
||||
output_data.emplace("id", manifest.mod_id);
|
||||
output_data.emplace("version", manifest.version_string);
|
||||
output_data.emplace("display_name", manifest.display_name);
|
||||
|
||||
if (!manifest.description.empty()) {
|
||||
output_data.emplace("description", manifest.description);
|
||||
}
|
||||
|
||||
if (!manifest.short_description.empty()) {
|
||||
output_data.emplace("short_description", manifest.short_description);
|
||||
}
|
||||
|
||||
print_vector_elements(output_file, manifest.authors, false);
|
||||
output_data.emplace("authors", string_vector_to_toml(manifest.authors));
|
||||
|
||||
fmt::print(output_file,
|
||||
" ],\n"
|
||||
" \"minimum_recomp_version\": \"{}\"",
|
||||
manifest.minimum_recomp_version);
|
||||
output_data.emplace("minimum_recomp_version", manifest.minimum_recomp_version);
|
||||
|
||||
if (!manifest.native_libraries.empty()) {
|
||||
fmt::print(output_file, ",\n"
|
||||
" \"native_libraries\": {{\n");
|
||||
toml::table libraries_table{};
|
||||
|
||||
size_t library_index = 0;
|
||||
for (const auto& [library, funcs] : manifest.native_libraries) {
|
||||
fmt::print(output_file, " \"{}\": [ ",
|
||||
library);
|
||||
print_vector_elements(output_file, funcs, true);
|
||||
fmt::print(output_file, "]{}\n",
|
||||
library_index == manifest.native_libraries.size() - 1 ? "" : ",");
|
||||
library_index++;
|
||||
libraries_table.emplace(library, string_vector_to_toml(funcs));
|
||||
}
|
||||
fmt::print(output_file, " }}");
|
||||
|
||||
output_data.emplace("native_libraries", std::move(libraries_table));
|
||||
}
|
||||
|
||||
if (!manifest.full_dependency_strings.empty()) {
|
||||
fmt::print(output_file, ",\n"
|
||||
" \"dependencies\": [\n");
|
||||
print_vector_elements(output_file, manifest.full_dependency_strings, false);
|
||||
fmt::print(output_file, " ]");
|
||||
output_data.emplace("dependencies", string_vector_to_toml(manifest.full_dependency_strings));
|
||||
}
|
||||
|
||||
toml::json_formatter formatter{output_data, toml::format_flags::indentation | toml::format_flags::indentation};
|
||||
std::ofstream output_file(path);
|
||||
|
||||
fmt::print(output_file, "\n}}\n");
|
||||
output_file << formatter << std::endl;
|
||||
}
|
||||
|
||||
N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, bool& good) {
|
||||
|
@ -589,6 +589,16 @@ namespace N64Recomp {
|
||||
return vram >= 0x8F000000 && vram < 0x90000000;
|
||||
}
|
||||
|
||||
// Locale-independent ASCII-only version of isalpha.
|
||||
inline bool isalpha_nolocale(char c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
// Locale-independent ASCII-only version of isalnum.
|
||||
inline bool isalnum_nolocale(char c) {
|
||||
return isalpha_nolocale(c) || (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
inline bool validate_mod_id(std::string_view str) {
|
||||
// Disallow empty ids.
|
||||
if (str.size() == 0) {
|
||||
@ -604,13 +614,13 @@ namespace N64Recomp {
|
||||
// so this is just to prevent "weird" mod ids.
|
||||
|
||||
// Check the first character, which must be alphabetical or an underscore.
|
||||
if (!isalpha(str[0]) && str[0] != '_') {
|
||||
if (!isalpha_nolocale(str[0]) && str[0] != '_') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the remaining characters, which can be alphanumeric or underscore.
|
||||
for (char c : str.substr(1)) {
|
||||
if (!isalnum(c) && c != '_') {
|
||||
if (!isalnum_nolocale(c) && c != '_') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user