1+ #pragma once
2+
3+ #include " game/save_file.h"
4+
5+ #include < nlohmann/json.hpp>
6+
7+ using json = nlohmann::json;
8+
9+ #define SAVE_FILE_VERSION 1
10+
11+ static std::string entries[] = {
12+ " CG" , " BOB" , " WF" , " JRB" , " CCM" , " BBH" , " HMC" , " LLL" , " SSL" , " DDD" , " SL" ,
13+ " WDW" , " TTM" , " THI" , " TTC" , " RR" , " BITDW" , " BITFS" , " BITS" , " PSS" , " COTMC" ,
14+ " TOTWC" , " VCUTM" , " WMOTR" , " SA" , " CAKE_END"
15+ };
16+
17+ template <typename T>
18+ T GetSafeEntry (const json& node, const std::string& key) {
19+ if (!node.contains (key)) {
20+ auto dump = nlohmann::json (node).dump (4 );
21+ throw std::runtime_error (" JSON missing the '" + key + " ' entry\n Problematic JSON:\n " + dump);
22+ }
23+
24+ return node.at (key).get <T>();
25+ }
26+
27+ template <typename T>
28+ T GetSafeEntry (const json& node, const std::string& key, const T& def) {
29+ if (!node.contains (key)) {
30+ return def;
31+ }
32+
33+ return node.at (key).get <T>();
34+ }
35+
36+ inline void to_json (json& j, const SaveFile& save) {
37+ json stars = {};
38+ json coins = {};
39+ json cap = {
40+ { " x" , save.capPos [0 ] },
41+ { " y" , save.capPos [1 ] },
42+ { " z" , save.capPos [2 ] },
43+ };
44+ for (size_t i = 0 ; i < COURSE_COUNT ; i++) {
45+ stars[entries[i]] = save.courseStars [i];
46+ }
47+
48+ for (size_t i = 0 ; i < COURSE_STAGES_COUNT ; i++) {
49+ coins[entries[i]] = save.courseCoinScores [i];
50+ }
51+
52+ j = json{
53+ { " version" , SAVE_FILE_VERSION },
54+ { " capLevel" , save.capLevel },
55+ { " capArea" , save.capArea },
56+ { " capPos" , cap },
57+ { " flags" , save.flags },
58+ { " courseStars" , stars },
59+ { " courseCoinScores" , coins }
60+ };
61+ }
62+
63+ inline void LoadSaveFileV1 (const json& j, SaveFile& save) {
64+ json capPosJson = GetSafeEntry<json>(j, " capPos" );
65+ save.capLevel = GetSafeEntry (j, " capLevel" , 0 );
66+ save.capArea = GetSafeEntry (j, " capArea" , 0 );
67+ save.capPos [0 ] = GetSafeEntry (capPosJson, " x" , 0 );
68+ save.capPos [1 ] = GetSafeEntry (capPosJson, " y" , 0 );
69+ save.capPos [2 ] = GetSafeEntry (capPosJson, " z" , 0 );
70+ save.flags = GetSafeEntry (j, " flags" , 0 );
71+
72+ json starsJson = GetSafeEntry<json>(j, " courseStars" );
73+ for (size_t i = 0 ; i < COURSE_COUNT ; i++) {
74+ save.courseStars [i] = GetSafeEntry<u8 >(starsJson, entries[i]);
75+ }
76+
77+ json coinsJson = GetSafeEntry<json>(j, " courseCoinScores" );
78+ for (size_t i = 0 ; i < COURSE_STAGES_COUNT ; i++) {
79+ save.courseCoinScores [i] = GetSafeEntry<u8 >(coinsJson, entries[i]);
80+ }
81+ }
82+
83+ inline void from_json (const json& j, SaveFile& save) {
84+ uint32_t version = GetSafeEntry<uint32_t >(j, " version" );
85+ if (version == 1 ) {
86+ LoadSaveFileV1 (j, save);
87+ }
88+ }
89+
90+ inline void to_json (json& j, const MainMenuSaveData& menu) {
91+ json coins = json::array ();
92+ for (size_t i = 0 ; i < NUM_SAVE_FILES ; i++) {
93+ coins.push_back (menu.coinScoreAges [i]);
94+ }
95+
96+ j = json{
97+ { " version" , SAVE_FILE_VERSION },
98+ { " coinScoreAges" , coins },
99+ { " soundMode" , menu.soundMode }
100+ };
101+ }
102+
103+ inline void LoadMainMenuSaveDataV1 (const json& j, MainMenuSaveData& menu) {
104+ json coinsJson = GetSafeEntry<json>(j, " coinScoreAges" );
105+ for (size_t i = 0 ; i < NUM_SAVE_FILES ; i++) {
106+ menu.coinScoreAges [i] = coinsJson.at (i).get <u32 >();
107+ }
108+
109+ menu.soundMode = GetSafeEntry<u16 >(j, " soundMode" , 0 );
110+ }
111+
112+ inline void from_json (const json& j, MainMenuSaveData& menu) {
113+ uint32_t version = GetSafeEntry<uint32_t >(j, " version" );
114+ if (version == 1 ) {
115+ LoadMainMenuSaveDataV1 (j, menu);
116+ }
117+ }
0 commit comments