2022-03-16 02:10:18 +01:00
|
|
|
#include "better_song.hpp"
|
2022-03-27 03:32:13 +02:00
|
|
|
|
2022-04-02 04:10:09 +02:00
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include <fmt/core.h>
|
2022-03-23 02:20:07 +01:00
|
|
|
#include <SFML/System/Time.hpp>
|
2022-03-16 02:10:18 +01:00
|
|
|
|
2022-03-31 03:50:15 +02:00
|
|
|
#include "better_hakus.hpp"
|
2022-04-02 04:10:09 +02:00
|
|
|
#include "better_timing.hpp"
|
2022-03-31 03:50:15 +02:00
|
|
|
#include "json.hpp"
|
2022-04-02 04:10:09 +02:00
|
|
|
#include "src/better_chart.hpp"
|
2022-03-31 03:50:15 +02:00
|
|
|
#include "src/better_hakus.hpp"
|
2022-04-02 04:10:09 +02:00
|
|
|
#include "src/better_metadata.hpp"
|
|
|
|
#include "src/better_note.hpp"
|
|
|
|
#include "src/special_numeric_types.hpp"
|
2022-03-27 03:32:13 +02:00
|
|
|
#include "std_optional_extras.hpp"
|
2022-03-31 03:50:15 +02:00
|
|
|
#include "variant_visitor.hpp"
|
2022-03-27 03:32:13 +02:00
|
|
|
|
2022-03-16 02:10:18 +01:00
|
|
|
namespace better {
|
2022-03-31 03:50:15 +02:00
|
|
|
std::string stringify_level(std::optional<Decimal> level) {
|
|
|
|
return stringify_or(level, "(no level defined)");
|
2022-03-16 02:10:18 +01:00
|
|
|
};
|
|
|
|
|
2022-04-02 04:10:09 +02:00
|
|
|
nlohmann::ordered_json Song::dump_to_memon_1_0_0() const {
|
2022-03-31 03:50:15 +02:00
|
|
|
nlohmann::ordered_json memon;
|
|
|
|
memon["version"] = "1.0.0";
|
2022-04-02 04:10:09 +02:00
|
|
|
auto json_metadata = metadata.dump_to_memon_1_0_0();
|
2022-03-31 03:50:15 +02:00
|
|
|
if (not json_metadata.empty()) {
|
|
|
|
memon["metadata"] = json_metadata;
|
|
|
|
}
|
2022-04-01 01:41:47 +02:00
|
|
|
nlohmann::json fallback_timing_object = R"(
|
2022-04-03 15:59:05 +02:00
|
|
|
{"offset": "0", "resolution": 240, "bpms": [{"beat": 0, "bpm": "120"}]}
|
2022-04-01 01:41:47 +02:00
|
|
|
)"_json;
|
|
|
|
auto song_timing = dump_memon_1_0_0_timing_object(timing, hakus, fallback_timing_object);
|
|
|
|
if (not song_timing.empty()) {
|
|
|
|
memon["timing"] = song_timing;
|
2022-03-31 03:50:15 +02:00
|
|
|
}
|
2022-04-01 01:41:47 +02:00
|
|
|
fallback_timing_object.update(song_timing);
|
2022-03-31 03:50:15 +02:00
|
|
|
auto json_charts = nlohmann::ordered_json::object();
|
|
|
|
for (const auto& [name, chart] : charts) {
|
2022-04-02 04:10:09 +02:00
|
|
|
json_charts[name] = chart.dump_to_memon_1_0_0(fallback_timing_object);
|
2022-03-31 03:50:15 +02:00
|
|
|
}
|
|
|
|
return memon;
|
2022-03-23 02:20:07 +01:00
|
|
|
}
|
2022-04-02 04:10:09 +02:00
|
|
|
|
|
|
|
Song Song::load_from_memon(const nlohmann::json& memon) {
|
|
|
|
if (not memon.is_object()) {
|
|
|
|
throw std::invalid_argument(
|
|
|
|
"The json file you tried to load does not contain an object "
|
|
|
|
"at the top level. This is required for a json file to be a "
|
|
|
|
"valid memon file."
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (not memon.contains("version")) {
|
|
|
|
return Song::load_from_memon_legacy(memon);
|
|
|
|
}
|
|
|
|
if (not memon["version"].is_string()) {
|
|
|
|
throw std::invalid_argument(
|
|
|
|
"The json file you tried to load has a 'version' key at the "
|
|
|
|
"top level but its associated value is not a string. This is "
|
|
|
|
"required for a json file to be a valid memon file."
|
|
|
|
);
|
|
|
|
}
|
|
|
|
const auto version = memon["version"].get<std::string>();
|
|
|
|
if (version == "1.0.0") {
|
|
|
|
return Song::load_from_memon_1_0_0(memon);
|
|
|
|
} else if (version == "0.3.0") {
|
|
|
|
return Song::load_from_memon_0_3_0(memon);
|
|
|
|
} else if (version == "0.2.0") {
|
|
|
|
return Song::load_from_memon_0_2_0(memon);
|
|
|
|
} else if (version == "0.1.0") {
|
|
|
|
return Song::load_from_memon_0_1_0(memon);
|
|
|
|
} else {
|
|
|
|
throw std::invalid_argument(fmt::format(
|
|
|
|
"Unknown memon version : {}",
|
|
|
|
version
|
|
|
|
));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Song Song::load_from_memon_1_0_0(const nlohmann::json& memon) {
|
2022-04-03 15:59:05 +02:00
|
|
|
Metadata metadata;
|
|
|
|
if (memon.contains("metadata")) {
|
|
|
|
metadata = Metadata::load_from_memon_1_0_0(memon["metadata"]);
|
|
|
|
}
|
|
|
|
nlohmann::json song_timing_json = R"(
|
|
|
|
{"offset": "0", "resolution": 240, "bpms": [{"beat": 0, "bpm": "120"}]}
|
|
|
|
)"_json;
|
|
|
|
if (memon.contains("timing")) {
|
|
|
|
song_timing_json.update(memon["timing"]);
|
|
|
|
}
|
|
|
|
const auto song_timing = Timing::load_from_memon_1_0_0(song_timing_json);
|
|
|
|
const auto hakus = load_hakus(song_timing_json);
|
|
|
|
Song song{
|
|
|
|
.charts = {},
|
|
|
|
.metadata = metadata,
|
|
|
|
.timing = song_timing,
|
|
|
|
.hakus = hakus
|
|
|
|
};
|
|
|
|
for (const auto& [dif, chart_json] : memon["data"].items()) {
|
|
|
|
const auto chart = Chart::load_from_memon_1_0_0(chart_json, song_timing_json);
|
|
|
|
song.charts[dif] = chart;
|
|
|
|
}
|
|
|
|
return song;
|
2022-04-02 04:10:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Song Song::load_from_memon_0_3_0(const nlohmann::json& memon) {
|
2022-04-03 15:59:05 +02:00
|
|
|
const auto json_metadata = memon["metadata"];
|
|
|
|
const auto metadata = Metadata::load_from_memon_0_3_0(memon["metadata"]);
|
|
|
|
const auto timing = Timing::load_from_memon_legacy(json_metadata);
|
|
|
|
Song song{
|
|
|
|
.charts = {},
|
|
|
|
.metadata = metadata,
|
|
|
|
.timing = timing,
|
|
|
|
.hakus = {}
|
|
|
|
};
|
|
|
|
for (const auto& [dif, chart_json] : memon["data"].items()) {
|
|
|
|
const auto chart = Chart::load_from_memon_legacy(chart_json);
|
|
|
|
song.charts[dif] = chart;
|
|
|
|
}
|
|
|
|
return song;
|
2022-04-02 04:10:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Song Song::load_from_memon_0_2_0(const nlohmann::json& memon) {
|
2022-04-03 15:59:05 +02:00
|
|
|
const auto json_metadata = memon["metadata"];
|
|
|
|
const auto metadata = Metadata::load_from_memon_0_2_0(memon["metadata"]);
|
|
|
|
const auto timing = Timing::load_from_memon_legacy(json_metadata);
|
|
|
|
Song song{
|
|
|
|
.charts = {},
|
|
|
|
.metadata = metadata,
|
|
|
|
.timing = timing,
|
|
|
|
.hakus = {}
|
|
|
|
};
|
|
|
|
for (const auto& [dif, chart_json] : memon["data"].items()) {
|
|
|
|
const auto chart = Chart::load_from_memon_legacy(chart_json);
|
|
|
|
song.charts[dif] = chart;
|
|
|
|
}
|
|
|
|
return song;
|
2022-04-02 04:10:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Song Song::load_from_memon_0_1_0(const nlohmann::json& memon) {
|
2022-04-03 15:59:05 +02:00
|
|
|
const auto json_metadata = memon["metadata"];
|
|
|
|
const auto metadata = Metadata::load_from_memon_0_1_0(memon["metadata"]);
|
|
|
|
const auto timing = Timing::load_from_memon_legacy(json_metadata);
|
|
|
|
Song song{
|
|
|
|
.charts = {},
|
|
|
|
.metadata = metadata,
|
|
|
|
.timing = timing,
|
|
|
|
.hakus = {}
|
|
|
|
};
|
|
|
|
for (const auto& [dif, chart_json] : memon["data"].items()) {
|
|
|
|
const auto chart = Chart::load_from_memon_legacy(chart_json);
|
|
|
|
song.charts[dif] = chart;
|
|
|
|
}
|
|
|
|
return song;
|
2022-04-02 04:10:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Song Song::load_from_memon_legacy(const nlohmann::json& memon) {
|
|
|
|
const auto json_metadata = memon["metadata"];
|
|
|
|
const auto metadata = Metadata::load_from_memon_legacy(memon["metadata"]);
|
2022-04-03 15:59:05 +02:00
|
|
|
const auto timing = Timing::load_from_memon_legacy(json_metadata);
|
2022-04-02 04:10:09 +02:00
|
|
|
Song song{
|
|
|
|
.charts = {},
|
|
|
|
.metadata = metadata,
|
|
|
|
.timing = timing,
|
|
|
|
.hakus = {}
|
|
|
|
};
|
|
|
|
for (const auto& chart_json : memon["data"]) {
|
|
|
|
const auto dif = chart_json["dif_name"].get<std::string>();
|
2022-04-03 15:59:05 +02:00
|
|
|
const auto chart = Chart::load_from_memon_legacy(chart_json);
|
2022-04-02 04:10:09 +02:00
|
|
|
song.charts[dif] = chart;
|
|
|
|
}
|
|
|
|
return song;
|
|
|
|
};
|
2022-03-16 02:10:18 +01:00
|
|
|
}
|