1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
#pragma once
#include <nlohmann/json.hpp>
#include "entry.h"
#include "defines.h"
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <memory>
#include <optional>
#include <stdexcept>
#include <filesystem>
namespace nlohmann {
template <typename T> struct adl_serializer<std::shared_ptr<T>> {
static void to_json(json& j, const std::shared_ptr<T>& opt) {
if(opt) {
j = opt->serialize();
} else {
j = nullptr;
}
}
static void from_json(const json& j, std::shared_ptr<T>& opt) {
opt = std::shared_ptr<T>(T::create(j));
}
};
template <typename T> struct adl_serializer<std::optional<T>> {
static void to_json(json& j, const std::optional<T>& opt) {
if(opt) {
j = *opt;
} else {
j = nullptr;
}
}
static void from_json(const json& j, std::optional<T>& opt) {
if(j.is_null()) {
opt = std::optional<T>();
} else {
opt = j.get<T>();
}
}
};
}
namespace utils {
nlohmann::json loadJson(const std::filesystem::path& path);
// Recursively loads all .json files under directory
// If called multiple times with same directory, returns a cached result.
std::vector<nlohmann::json> loadAllJson(const std::string& directory);
// looks up directory in settings. Returns element matching name.
nlohmann::json loadJson(const std::string& type, const std::string& name);
// goes through the available types and searches for the one matching name.
nlohmann::json findByName(const std::string& name);
void saveJson(const nlohmann::json& data, const std::filesystem::path& path);
// converts in-place
std::string lower(std::string& in);
template<typename T> std::shared_ptr<T> instantiate(const std::filesystem::path& path) {
std::shared_ptr<entry::Entry> ent;
try {
ent = entry::Entry::create(loadJson(path));
} catch(std::exception& e) {
if(std::filesystem::directory_entry(path).exists()) {
throw std::runtime_error("Invalid json: " + path.string() + ": " + e.what());
} else {
throw std::runtime_error("No such file nor directory: " + path.string());
}
}
std::shared_ptr<T> t = std::dynamic_pointer_cast<T>(ent);
if(! t) {
throw std::runtime_error("Wrong instance type: " + ent->getType());
}
return t;
}
int parseInt(const std::string& s);
template<typename S, typename D> std::shared_ptr<S> loadDFromJson(const nlohmann::json& data) {
nlohmann::json j = data;
try {
j = loadJson(data["type"], data["name"]);
} catch(std::exception& e) {
// Covers errors in building the creature or fs traversal.
// Fall back on the data passed in.
}
D *d = new D();
from_json(j, *d);
d->init();
return std::shared_ptr<S>(d);
}
template<typename F, typename T> std::vector<std::shared_ptr<T>> castPtrs(std::vector<std::shared_ptr<F>> from) {
std::vector<std::shared_ptr<T>> Ts;
for(std::shared_ptr<F> f : from) {
std::shared_ptr<T> t = std::dynamic_pointer_cast<T>(f);
if(t) {
Ts.push_back(t);
}
}
return Ts;
}
template<typename Container> std::string join(Container parts, std::string joiner) {
std::stringstream out;
bool isFirst = true;
for(auto p : parts) {
if(! isFirst) {
out << joiner;
}
isFirst = false;
out << p;
}
return out.str();
}
const std::map<std::string, int> cpValue {
{"cp", 1},
{"sp", 10},
{"ep", 50},
{"gp", 100},
{"pp", 1000}
};
// Accepts coins formatted "X Yp" where X is an integer and Y is any of c, s, e, g, p.
int coins2copper(const std::string& coins);
// Greedily selects highest coin values to minimize total number of coins
// Returns a vector of pairs mapping coin type to coint
std::vector<std::pair<std::string, int>> copper2coins(int coppers);
std::string getCostString(int coppers);
std::string toOrdinal(std::size_t number);
template<typename T> std::vector<T> json2vec(const nlohmann::json& data) {
using std::begin; using std::end;
return std::vector<T>(begin(data), end(data));
}
template<typename T> std::vector<std::shared_ptr<T>> instantiateNames(const std::string& type, const std::vector<std::string>& names) {
std::vector<std::shared_ptr<T>> ret;
for(auto name : names) {
ret.push_back(loadDFromJson<T, T>(utils::loadJson(type, name)));
}
return ret;
}
}
|