From d1c95742ddd83899bb35051de9d731d38aba80a4 Mon Sep 17 00:00:00 2001 From: E14 <1640391+E14@users.noreply.github.com> Date: Sun, 22 Sep 2019 22:57:54 +0200 Subject: Add ProtocolBlockTypePalette (#4391) --- src/Protocol/CMakeLists.txt | 3 + src/Protocol/ProtocolBlockTypePalette.cpp | 144 ++++++++++++++++++++++++++++++ src/Protocol/ProtocolBlockTypePalette.h | 40 +++++++++ 3 files changed, 187 insertions(+) create mode 100644 src/Protocol/ProtocolBlockTypePalette.cpp create mode 100644 src/Protocol/ProtocolBlockTypePalette.h (limited to 'src/Protocol') diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt index 127edd317..d2170fb95 100644 --- a/src/Protocol/CMakeLists.txt +++ b/src/Protocol/CMakeLists.txt @@ -1,3 +1,4 @@ +include_directories (SYSTEM "../../lib/jsoncpp/include") SET (SRCS Authenticator.cpp @@ -12,6 +13,7 @@ SET (SRCS Protocol_1_12.cpp Protocol_1_13.cpp ProtocolRecognizer.cpp + ProtocolBlockTypePalette.cpp ) SET (HDRS @@ -28,6 +30,7 @@ SET (HDRS Protocol_1_12.h Protocol_1_13.h ProtocolRecognizer.h + ProtocolBlockTypePalette.h ) if (NOT MSVC) diff --git a/src/Protocol/ProtocolBlockTypePalette.cpp b/src/Protocol/ProtocolBlockTypePalette.cpp new file mode 100644 index 000000000..86d05623b --- /dev/null +++ b/src/Protocol/ProtocolBlockTypePalette.cpp @@ -0,0 +1,144 @@ +#include "Globals.h" +#include "ProtocolBlockTypePalette.h" +#include +#include +#include "json/value.h" +#include "json/reader.h" + + + + + +ProtocolBlockTypePalette::ProtocolBlockTypePalette() +{ + // empty +} + + + + + +bool ProtocolBlockTypePalette::loadFromString(const AString & aMapping) +{ + std::stringstream stream; + stream << aMapping; + + return loadFromStream(stream); +} + + + + + +bool ProtocolBlockTypePalette::loadFromStream(std::istream & aInputStream) +{ + Json::Value root; + + try + { + aInputStream >> root; + } + #if defined _DEBUG + catch (const std::exception & e) + { + LOGD(e.what()); + return false; + } + #else + catch (const std::exception &) + { + return false; + } + #endif + + if (!root.isObject() || + !root.isMember("Metadata") || + !root["Metadata"].isMember("ProtocolBlockTypePaletteVersion") || + !root.isMember("Palette") || + !root["Palette"].isArray()) + { + LOGD("Incorrect palette format."); + return false; + } + + if (root["Metadata"]["ProtocolBlockTypePaletteVersion"].asUInt() != 1) + { + LOGD("Palette format version not supported."); + return false; + } + + auto len = root["Palette"].size(); + for (decltype(len) i = 0; i < len; ++i) + { + const auto & record = root["Palette"][i]; + if (!record.isObject()) + { + LOGD("Record #%u must be a JSON object.", i); + return false; + } + + auto blocktype = record["name"].asString(); + auto id = std::stoul(record["id"].asString()); + std::map state; + + if (id >= NOT_FOUND) + { + LOGD("`id` must be less than ProtocolBlockTypePalette::NOT_FOUND, but is %lu", id); + return false; + } + + if (record.isMember("props")) + { + const auto & props = record["props"]; + if (!props.isObject()) + { + LOGD("`props` key must be a JSON object."); + return false; + } + for (const auto & key: props.getMemberNames()) + { + state[key] = props[key].asString(); + } + } + + // Block type map entry already exists? + if (mIndex.count(blocktype) == 0) + { + mIndex.insert({blocktype, std::map()}); + } + + const auto & result = mIndex[blocktype].insert({BlockState(state), id}); + if (result.second == false) + { + LOGINFO("Duplicate block state encountered (Current ID: %lu, other: %lu)", result.first->second, id); + } + } + return true; +} + + + + + +UInt32 ProtocolBlockTypePalette::index(const AString & aBlockTypeName, const BlockState & aBlockState) const +{ + auto a = mIndex.find(aBlockTypeName); + if (a != mIndex.end()) + { + auto b = a->second.find(aBlockState); + if (b != a->second.end()) + { + return b->second; + } + } + return NOT_FOUND; +} + + + + + +void ProtocolBlockTypePalette::clear() +{ + return mIndex.clear(); +} diff --git a/src/Protocol/ProtocolBlockTypePalette.h b/src/Protocol/ProtocolBlockTypePalette.h new file mode 100644 index 000000000..fb156cfd5 --- /dev/null +++ b/src/Protocol/ProtocolBlockTypePalette.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include "../BlockState.h" + + +/** Parses and holds a collection of block types and their possible states +together with their corresponding Id within the Minecraft network protocol. */ +class ProtocolBlockTypePalette +{ +public: + static const UInt32 NOT_FOUND = UINT32_MAX; + + /** Create a new empty instance. */ + ProtocolBlockTypePalette(); + + /** Loads the palette from a string. + See loadFromStream() for further details. */ + bool loadFromString(const AString & aMapping); + + /** Loads the palette from an input stream. + Returns `true` on success, `false` otherwise. Sucessive calls to this method + will _add_ data to the palette. If duplicate keys are encountered, they will + be ignored and an info message logged. */ + bool loadFromStream(std::istream & aInputStream); + + /** Returns the defined index corresponding of the given aBlockTypeName and + aBlockState. + Returns ProtocolBlockTypePalette::NOT_FOUND if the tuple is not found. */ + UInt32 index(const AString & aBlockTypeName, const BlockState & aBlockState) const; + + /** Clears the palette. */ + void clear(); + + +protected: + + /** The palette index. Each item in the map represents a single block state + palette entry. The value is the block state ID. */ + std::unordered_map> mIndex; +}; -- cgit v1.2.3