3 #include "json/value.h"
15 for (
size_t i = aStartIdx, len = aString.length(); i < len; ++i)
45 auto idx =
maybeIndex(aBlockTypeName, aBlockState);
69 auto itr2 = itr1->second.find(aBlockState);
70 if (itr2 == itr1->second.end())
74 return {itr2->second,
true};
106 std::map<UInt32, UInt32> res;
109 auto fromIndex = fromEntry.first;
110 const auto & blockTypeName = fromEntry.second.first;
111 const auto & blockState = fromEntry.second.second;
112 res[fromIndex] =
index(blockTypeName, blockState);
123 std::map<UInt32, UInt32> res;
126 auto fromIndex = fromEntry.first;
127 const auto & blockTypeName = fromEntry.second.first;
128 const auto & blockState = fromEntry.second.second;
129 auto thisIndex =
maybeIndex(blockTypeName, blockState);
130 if (thisIndex.second)
133 res[fromIndex] = thisIndex.first;
138 res[fromIndex] = aFallbackIndex;
150 static const AString hdrTsvRegular =
"BlockTypePalette";
151 static const AString hdrTsvUpgrade =
"UpgradeBlockTypePalette";
154 if (aString.substr(0, hdrTsvRegular.length()) == hdrTsvRegular)
158 else if (aString.substr(0, hdrTsvUpgrade.length()) == hdrTsvUpgrade)
180 if (!root.isObject())
186 for (
auto itr = root.begin(), end = root.end(); itr != end; ++itr)
188 const auto & blockTypeName = itr.name();
189 const auto & states = (*itr)[
"states"];
190 if (states == Json::Value())
192 throw LoadFailedException(fmt::format(FMT_STRING(
"Missing \"states\" for block type \"{}\""), blockTypeName));
194 for (
const auto & state: states)
196 auto id =
static_cast<UInt32>(std::stoul(state[
"id"].asString()));
197 std::map<AString, AString> props;
198 if (state.isMember(
"properties"))
200 const auto & properties = state[
"properties"];
201 if (!properties.isObject())
203 throw LoadFailedException(fmt::format(FMT_STRING(
"Member \"properties\" is not a JSON object (block type \"{}\", id {})."), blockTypeName,
id));
205 for (
const auto & key: properties.getMemberNames())
207 props[key] = properties[key].asString();
221 static const AString hdrTsvRegular =
"BlockTypePalette";
222 static const AString hdrTsvUpgrade =
"UpgradeBlockTypePalette";
226 if ((idx == AString::npos) || (aTsvPalette[idx] ==
'\t'))
230 auto signature = aTsvPalette.substr(0, idx);
231 bool isUpgrade = (signature == hdrTsvUpgrade);
232 if (!isUpgrade && (signature != hdrTsvRegular))
236 if (aTsvPalette[idx] ==
'\r')
242 bool hasHadVersion =
false;
245 auto len = aTsvPalette.length();
248 auto keyStart = idx + 1;
250 if (keyEnd == AString::npos)
252 throw LoadFailedException(fmt::format(FMT_STRING(
"Invalid header key format on line {}"), line));
254 if (keyEnd == idx + 1)
256 if (aTsvPalette[keyEnd] ==
'\r')
265 if ((valueEnd == AString::npos) || (aTsvPalette[valueEnd] ==
'\t'))
267 throw LoadFailedException(fmt::format(FMT_STRING(
"Invalid header value format on line {}"), line));
269 auto key = aTsvPalette.substr(keyStart, keyEnd - keyStart);
270 if (key ==
"FileVersion")
272 unsigned version = 0;
273 auto value = aTsvPalette.substr(keyEnd + 1, valueEnd - keyEnd - 1);
278 else if (version != 1)
280 throw LoadFailedException(fmt::format(FMT_STRING(
"Unknown FileVersion: {}. Only version 1 is supported."), version));
282 hasHadVersion =
true;
284 else if (key ==
"CommonPrefix")
286 commonPrefix = aTsvPalette.substr(keyEnd + 1, valueEnd - keyEnd - 1);
289 if (aTsvPalette[idx] ==
'\r')
301 while (idx + 1 < len)
303 auto lineStart = idx + 1;
305 if ((idEnd == AString::npos) || (aTsvPalette[idEnd] !=
'\t'))
307 throw LoadFailedException(fmt::format(FMT_STRING(
"Incomplete data on line {} (id)"), line));
310 if (!
StringToInteger(aTsvPalette.substr(lineStart, idEnd - lineStart),
id))
314 size_t metaEnd = idEnd;
318 if ((metaEnd == AString::npos) || (aTsvPalette[metaEnd] !=
'\t'))
320 throw LoadFailedException(fmt::format(FMT_STRING(
"Incomplete data on line {} (meta)"), line));
323 if (!
StringToInteger(aTsvPalette.substr(idEnd + 1, metaEnd - idEnd - 1), meta))
325 throw LoadFailedException(fmt::format(FMT_STRING(
"Failed to parse meta on line {}"), line));
329 throw LoadFailedException(fmt::format(FMT_STRING(
"Invalid meta value on line {}: {}"), line, meta));
331 id = (
id * 16) | meta;
334 if (blockTypeEnd == AString::npos)
336 throw LoadFailedException(fmt::format(FMT_STRING(
"Incomplete data on line {} (blockTypeName)"), line));
338 auto blockTypeName = aTsvPalette.substr(metaEnd + 1, blockTypeEnd - metaEnd - 1);
339 auto blockStateEnd = blockTypeEnd;
341 while (aTsvPalette[blockStateEnd] ==
'\t')
344 if ((keyEnd == AString::npos) || (aTsvPalette[keyEnd] !=
'\t'))
346 throw LoadFailedException(fmt::format(FMT_STRING(
"Incomplete data on line {} (blockState key)"), line));
349 if (valueEnd == AString::npos)
351 throw LoadFailedException(fmt::format(FMT_STRING(
"Incomplete data on line {} (blockState value)"), line));
353 auto key = aTsvPalette.substr(blockStateEnd + 1, keyEnd - blockStateEnd - 1);
354 auto value = aTsvPalette.substr(keyEnd + 1, valueEnd - keyEnd - 1);
355 blockState[key] = value;
356 blockStateEnd = valueEnd;
358 addMapping(
id, commonPrefix + blockTypeName, std::move(blockState));
360 if (aTsvPalette[blockStateEnd] ==
'\r')
static size_t findNextSeparator(const AString &aString, size_t aStartIdx=0)
Returns the index into aString >= aStartIdx at which the next separator occurs.
bool StringToInteger(const AString &a_str, T &a_Num)
Parses any integer type.
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
bool ParseString(const AString &a_JsonStr, Json::Value &a_Root, AString *a_ErrorMsg)
Represents the state of a single block (previously known as "block meta").
Holds a palette that maps between block type + state and numbers.
std::map< UInt32, UInt32 > createTransformMapAddMissing(const BlockTypePalette &aFrom)
Returns an index-transform map from aFrom to this (this.entry(idx) == aFrom.entry(res[idx])).
void loadFromString(const AString &aString)
Loads the palette from the string representation.
void loadFromTsv(const AString &aTsvPalette, bool aIsUpgrade)
Loads the palette from the regular or upgrade TSV representation.
std::pair< UInt32, bool > maybeIndex(const AString &aBlockTypeName, const BlockState &aBlockState) const
Returns the <index, true> of the specified block type name and state, if it exists.
std::unordered_map< AString, std::map< BlockState, UInt32 > > mBlockToNumber
The mapping from stringular to numeric representation.
UInt32 count() const
Returns the total number of entries in the palette.
void loadFromJsonString(const AString &aJsonPalette)
Loads the palette from the JSON representation, https://wiki.vg/Data_Generators Throws a LoadFailedEx...
UInt32 index(const AString &aBlockTypeName, const BlockState &aBlockState)
Returns the index of the specified block type name and state.
std::map< UInt32, UInt32 > createTransformMapWithFallback(const BlockTypePalette &aFrom, UInt32 aFallbackIndex) const
Returns an index-transform map from aFrom to this (this.entry(idx) == aFrom.entry(res[idx])).
const std::pair< AString, BlockState > & entry(UInt32 aIndex) const
Returns the blockspec represented by the specified palette index.
std::map< UInt32, std::pair< AString, BlockState > > mNumberToBlock
The mapping from numeric to stringular representation.
void addMapping(UInt32 aID, const AString &aBlockTypeName, const BlockState &aBlockState)
Adds a mapping between the numeric and stringular representation into both maps, updates the mMaxInde...
UInt32 mMaxIndex
The maximum index ever used in the maps.
BlockTypePalette()
Create a new empty instance.
Exception that is thrown if requiesting an index not present in the palette.
Exception that is thrown when loading the palette fails hard (bad format).