22 auto j = nlohmann::json::parse(text);
23 if (!j.is_object() || !j.contains(
"schema_version") ||
24 !j[
"schema_version"].is_number_integer() || j[
"schema_version"] != 1 ||
25 !Text(j,
"game_id") || !j.contains(
"entries") ||
26 !j[
"entries"].is_array()) {
28 "Terrain catalog requires schema_version 1, game_id and entries "
31 std::set<std::string> ids;
32 for (
const auto& entry : j[
"entries"]) {
33 if (!entry.is_object() || !Text(entry,
"id") || !Text(entry,
"name") ||
34 !Text(entry,
"category") || !Text(entry,
"review_state") ||
35 !entry.contains(
"bindings") || !entry[
"bindings"].is_array()) {
37 "Terrain entry requires id, name, category, review_state and "
40 if (!ids.insert(entry[
"id"].get<std::string>()).second) {
41 return Invalid(
"Duplicate terrain entry id");
43 const auto state = entry[
"review_state"].get<std::string>();
44 if (state !=
"suggested" && state !=
"reviewed") {
45 return Invalid(
"Terrain review_state must be suggested or reviewed");
47 if (entry.contains(
"tags")) {
48 if (!entry[
"tags"].is_array())
49 return Invalid(
"Terrain tags must be an array");
50 for (
const auto& tag : entry[
"tags"]) {
52 return Invalid(
"Terrain tags must be strings");
55 for (
const auto& binding : entry[
"bindings"]) {
56 if (!binding.is_object() || !Text(binding,
"adapter") ||
57 !Text(binding,
"definition_fingerprint") ||
58 !Text(binding,
"profile_fingerprint") ||
59 !binding.contains(
"tile_id") ||
60 !binding[
"tile_id"].is_number_integer() || binding[
"tile_id"] < 0 ||
61 binding[
"tile_id"] > 0x7fffffff) {
63 "Terrain binding requires adapter, nonnegative tile_id and exact "
69 }
catch (
const nlohmann::json::exception& e) {
70 return absl::InvalidArgumentError(std::string(
"Invalid terrain catalog: ") +
77 std::string_view adapter,
int tile_id, std::string_view definition,
78 std::string_view profile)
const {
79 std::vector<nlohmann::json> result;
80 for (
const auto& entry :
document_[
"entries"]) {
81 for (
const auto& binding : entry[
"bindings"]) {
82 if (std::string_view(binding[
"adapter"].get_ref<const std::string&>()) ==
84 binding[
"tile_id"] == tile_id &&
85 std::string_view(binding[
"definition_fingerprint"]
86 .get_ref<const std::string&>()) == definition &&
88 binding[
"profile_fingerprint"].get_ref<const std::string&>()) ==
90 result.push_back(entry);
99 uint64_t hash = 14695981039346656037ULL;
100 for (
unsigned char byte : bytes) {
102 hash *= 1099511628211ULL;
104 std::ostringstream stream;
105 stream <<
"fnv1a64:" << std::hex << std::setfill(
'0') << std::setw(16)