F.E.I.S/src/better_song.cpp

210 lines
7.5 KiB
C++
Raw Normal View History

#include "better_song.hpp"
#include <algorithm>
2022-04-02 04:10:09 +02:00
#include <stdexcept>
#include <fmt/core.h>
#include <json.hpp>
2022-03-23 02:20:07 +01:00
#include <SFML/System/Time.hpp>
#include "better_chart.hpp"
#include "better_hakus.hpp"
#include "better_metadata.hpp"
#include "better_note.hpp"
#include "better_hakus.hpp"
2022-04-02 04:10:09 +02:00
#include "better_timing.hpp"
#include "special_numeric_types.hpp"
#include "variant_visitor.hpp"
namespace better {
std::string stringify_level(std::optional<Decimal> level) {
2022-04-09 00:54:06 +02:00
if (level) {
return level->format("f");
} else {
return "(no level defined)";
}
};
2022-04-04 22:03:10 +02:00
std::tuple<int, std::string> difficulty_name_comp_key(const std::string& s) {
if (s == "BSC") {
return std::make_tuple(1, std::string{});
} else if (s == "ADV") {
return std::make_tuple(2, std::string{});
} else if (s == "EXT") {
return std::make_tuple(3, std::string{});
} else {
return std::make_tuple(4, s);
}
};
2022-04-06 15:47:04 +02:00
bool OrderByDifficultyName::operator()(const std::string& a, const std::string& b) const {
2022-04-04 22:03:10 +02:00
return difficulty_name_comp_key(a) < difficulty_name_comp_key(b);
};
2022-04-02 04:10:09 +02:00
nlohmann::ordered_json Song::dump_to_memon_1_0_0() const {
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();
if (not json_metadata.empty()) {
memon["metadata"] = json_metadata;
}
nlohmann::json fallback_timing_object = R"(
2022-04-03 15:59:05 +02:00
{"offset": "0", "resolution": 240, "bpms": [{"beat": 0, "bpm": "120"}]}
)"_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;
}
fallback_timing_object.update(song_timing);
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);
}
memon["data"] = json_charts;
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"]);
}
2022-10-26 02:08:19 +02:00
const auto song_timing = std::make_shared<Timing>(Timing::load_from_memon_1_0_0(song_timing_json));
2022-04-03 15:59:05 +02:00
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"]);
2022-10-26 02:08:19 +02:00
const auto timing = std::make_shared<Timing>(Timing::load_from_memon_legacy(json_metadata));
2022-04-03 15:59:05 +02:00
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"]);
2022-10-26 02:08:19 +02:00
const auto timing = std::make_shared<Timing>(Timing::load_from_memon_legacy(json_metadata));
2022-04-03 15:59:05 +02:00
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"]);
2022-10-26 02:08:19 +02:00
const auto timing = std::make_shared<Timing>(Timing::load_from_memon_legacy(json_metadata));
2022-04-03 15:59:05 +02:00
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-10-26 02:08:19 +02:00
const auto timing = std::make_shared<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;
};
bool Song::operator==(const Song& other) const {
return (
charts == other.charts
and metadata == other.metadata
and *timing == *other.timing
and hakus == other.hakus
);
}
std::ostream& operator<<(std::ostream& out, const Song& s) {
out << fmt::format("{}", s);
return out;
};
}