Skip to content

Commit

Permalink
feat: add nbt reflection API
Browse files Browse the repository at this point in the history
  • Loading branch information
OEOTYAN committed Dec 6, 2023
1 parent 390ecdb commit bb22afd
Show file tree
Hide file tree
Showing 14 changed files with 971 additions and 863 deletions.
2 changes: 1 addition & 1 deletion src/ll/api/command/DynamicCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ CommandParameterData DynamicCommand::ParameterData::makeParameterData() const {
case ParameterType::Command:
return makeParameterData<ParameterType::Command, ParameterDataType::Command>();
default:
return {};
std::unreachable();
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/ll/test/ConfigTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "ll/api/utils/WinUtils.h"
#include "mc/server/commands/standard/FillCommand.h"

#include "mc/nbt/CompoundTag.h"

template <class T>

class TestClass {
Expand Down Expand Up @@ -74,6 +76,8 @@ LL_AUTO_TYPED_INSTANCE_HOOK(

// ll::config::saveConfig(helloReflection, "plugins/Test/config/testconfig.json");

ll::logger.debug("reflection NBT: {}", ll::reflection::serialize<CompoundTagVariant>(helloReflection).dump(SnbtFormat::PrettyConsolePrint));

ll::logger.debug("0x{:X}", (uintptr_t)ll::memory::resolveIdentifier(&FillCommand::execute));
ll::logger.debug("0x{:X}", (uintptr_t)ll::win_utils::getImageRange().data());

Expand Down
3 changes: 2 additions & 1 deletion src/ll/test/TestNbt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ LL_AUTO_TYPED_INSTANCE_HOOK(NbtTest, HookPriority::Normal, ServerInstance, &Serv
some = {
new = { ; hi
compound = {
anull = null,
"byte" = 127b
"bytearray" = [B;1b, 2b, 3b, 4b, 5b, -2b, -3b, -6b], // orld /**/ /* 34t */
"compound" = {
Expand Down Expand Up @@ -125,5 +126,5 @@ LL_AUTO_TYPED_INSTANCE_HOOK(NbtTest, HookPriority::Normal, ServerInstance, &Serv
using namespace ll::string_utils;

ll::logger.debug("\n{}", replaceAnsiToMcCode(nbt.toSnbt(SnbtFormat::Colored | SnbtFormat::Console)));
ll::logger.debug("\n{}", (nbt.toSnbt(SnbtFormat::Colored)));
ll::logger.debug("\n{}", (nbt2.toSnbt(SnbtFormat::Colored)));
}
7 changes: 6 additions & 1 deletion src/mc/nbt/ByteArrayTag.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ class ByteArrayTag : public ::Tag {

ByteArrayTag() = default;

[[nodiscard]] constexpr ByteArrayTag(TagMemoryChunk mem) : data(std::move(mem)) {} // NOLINT
template <class T>
[[nodiscard]] constexpr ByteArrayTag(std::in_place_type_t<T>, TagMemoryChunk mem) : data(std::move(mem)) {
data.mSize = data.mSize * sizeof(T);
}

[[nodiscard]] constexpr ByteArrayTag(std::vector<schar> const& arr) : data(std::span{arr}) {} // NOLINT

std::span<schar> view() const { return std::span<schar>((schar*)data.mBuffer.get(), data.mSize); }

[[nodiscard]] constexpr schar& operator[](size_t index) const { return view()[index]; }

[[nodiscard]] constexpr size_t size() const { return data.mSize; }

public:
// NOLINTBEGIN
// vIndex: 0, symbol: __gen_??1ByteArrayTag@@UEAA@XZ
Expand Down
13 changes: 7 additions & 6 deletions src/mc/nbt/ByteTag.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ class ByteTag : public ::Tag {
public:
schar data;

constexpr ByteTag& operator=(schar value) {
data = value;
template <std::integral T>
constexpr ByteTag& operator=(T value) {
data = (schar)value;
return *this;
}

constexpr operator schar() const { return data; } // NOLINT
template <std::integral T>
constexpr operator T() const {
return (T)data;
}

template <std::integral T>
requires(sizeof(T) == 1)
[[nodiscard]] constexpr explicit ByteTag(T value = 0) : data((schar)value) {}

constexpr explicit operator bool() const { return data != 0; }

ByteTag operator-() const { return ByteTag{(schar)-data}; }

public:
Expand Down
87 changes: 80 additions & 7 deletions src/mc/nbt/CompoundTagVariant.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ class CompoundTagVariant {
case Tag::Type::IntArray:
mTagStorage = std::move((IntArrayTag&)*tag);
case Tag::Type::End:
default:
mTagStorage = std::move((EndTag&)*tag);
default:
std::unreachable();
}
}
[[nodiscard]] CompoundTagVariant(std::unique_ptr<Tag> const& tag) : CompoundTagVariant(std::move(tag->copy())) {}
Expand All @@ -97,12 +98,60 @@ class CompoundTagVariant {

[[nodiscard]] inline CompoundTagVariant(std::string s) : mTagStorage(StringTag{std::move(s)}) {} // NOLINT

[[nodiscard]] Tag::Type index() const { return (Tag::Type)mTagStorage.index(); }
[[nodiscard]] inline CompoundTagVariant(std::string_view s) : mTagStorage(StringTag{std::string(s)}) {} // NOLINT

[[nodiscard]] Tag::Type index() const noexcept { return (Tag::Type)mTagStorage.index(); }
template <std::derived_from<Tag> T>
[[nodiscard]] bool hold() const {
[[nodiscard]] bool hold() const noexcept {
return std::holds_alternative<T>(mTagStorage);
}

[[nodiscard]] bool is_array() const noexcept { return hold<ListTag>(); }
[[nodiscard]] bool is_binary() const noexcept { return hold<ByteArrayTag>() || hold<IntArrayTag>(); }
[[nodiscard]] bool is_boolean() const noexcept { return hold<ByteTag>(); }
[[nodiscard]] bool is_null() const noexcept { return hold<EndTag>(); }
[[nodiscard]] bool is_number_float() const noexcept { return hold<FloatTag>() || hold<DoubleTag>(); }
[[nodiscard]] bool is_number_integer() const noexcept {
return hold<ByteTag>() || hold<ShortTag>() || hold<IntTag>() || hold<Int64Tag>();
}
[[nodiscard]] bool is_number() const noexcept { return is_number_float() || is_number_integer(); }
[[nodiscard]] bool is_object() const noexcept { return hold<CompoundTag>(); }
[[nodiscard]] bool is_string() const noexcept { return hold<StringTag>(); }
[[nodiscard]] bool is_primitive() const noexcept { return is_null() || is_string() || is_number() || is_binary(); }
[[nodiscard]] bool is_structured() const noexcept { return is_array() || is_object(); }

[[nodiscard]] bool contains(std::string_view key) const noexcept {
if (is_object()) {
return get<CompoundTag>().contains(key);
}
return false;
}

[[nodiscard]] size_t size() const noexcept {
switch (index()) {
case Tag::Type::Byte:
case Tag::Type::Short:
case Tag::Type::Int:
case Tag::Type::Int64:
case Tag::Type::Float:
case Tag::Type::Double:
case Tag::Type::String:
return 1;
case Tag::Type::List:
return get<ListTag>().size();
case Tag::Type::Compound:
return get<CompoundTag>().size();
case Tag::Type::IntArray:
return get<IntArrayTag>().size();
case Tag::Type::ByteArray:
return get<ByteArrayTag>().size();
case Tag::Type::End:
return 0;
default:
std::unreachable();
}
}

template <std::derived_from<Tag> T>
[[nodiscard]] T& get() {
return std::get<T>(mTagStorage);
Expand All @@ -129,25 +178,49 @@ class CompoundTagVariant {
} else if (hold<ByteArrayTag>()) {
return get<ByteArrayTag>()[index];
} else {
throw std::range_error("tag not hold a integer index range");
throw std::range_error("tag not hold an array");
}
}

[[nodiscard]] CompoundTagVariant& operator[](std::string const& index) {
if (!hold<CompoundTag>()) {
if (hold<EndTag>()) {
mTagStorage = CompoundTag{};
}
if (!hold<CompoundTag>()) {
throw std::range_error("tag not hold an object");
}
return get<CompoundTag>()[index];
}

std::unique_ptr<Tag> toUnique() const {
std::unique_ptr<Tag> toUnique() const& {
return std::visit(
[](auto& val) -> std::unique_ptr<Tag> { return std::make_unique<std::decay_t<decltype(val)>>(val); },
mTagStorage
);
}

std::unique_ptr<Tag> toUnique() && {
return std::visit(
[](auto&& val) -> std::unique_ptr<Tag> {
return std::make_unique<std::decay_t<decltype(val)>>(std::forward<decltype(val)>(val));
return std::make_unique<std::decay_t<decltype(val)>>(std::move(val));
},
mTagStorage
);
}

std::string dump(SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint, uchar indent = 4) const {
return toUnique()->toSnbt(snbtFormat, indent);
}

void push_back(CompoundTagVariant val) {
if (hold<EndTag>()) {
mTagStorage = ListTag{};
}
if (!hold<ListTag>()) {
throw std::range_error("tag not hold an array");
}
get<ListTag>().add(std::move(val).toUnique());
}
};

#endif // COMPOUND_TAG_VARIANT_HEADER
9 changes: 6 additions & 3 deletions src/mc/nbt/Int64Tag.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ class Int64Tag : public ::Tag {
public:
int64 data;

template <std::integral T>
constexpr Int64Tag& operator=(int64 value) {
data = value;
data = (int64)value;
return *this;
}

constexpr operator int64() const { return data; } // NOLINT
template <std::integral T>
constexpr operator T() const {
return (T)data;
}

template <std::integral T>
requires(sizeof(T) == 8)
[[nodiscard]] constexpr explicit Int64Tag(T value = 0) : data((int64)value) {}

Int64Tag operator-() const { return Int64Tag{(int64)-data}; }
Expand Down
7 changes: 6 additions & 1 deletion src/mc/nbt/IntArrayTag.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ class IntArrayTag : public ::Tag {

[[nodiscard]] constexpr IntArrayTag() = default;

[[nodiscard]] constexpr IntArrayTag(TagMemoryChunk mem) : data(std::move(mem)) {} // NOLINT
template <class T>
[[nodiscard]] constexpr IntArrayTag(std::in_place_type_t<T>, TagMemoryChunk mem) : data(std::move(mem)) {
data.mSize = (data.mSize * sizeof(T)) / sizeof(int);
}

[[nodiscard]] constexpr IntArrayTag(std::vector<int> const& arr) : data(std::span{arr}) { // NOLINT
data.mSize = arr.size();
Expand All @@ -24,6 +27,8 @@ class IntArrayTag : public ::Tag {

[[nodiscard]] constexpr int& operator[](size_t index) const { return view()[index]; }

[[nodiscard]] constexpr size_t size() const { return data.mSize; }

public:
// NOLINTBEGIN
// vIndex: 0, symbol: __gen_??1IntArrayTag@@UEAA@XZ
Expand Down
9 changes: 6 additions & 3 deletions src/mc/nbt/IntTag.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ class IntTag : public ::Tag {
public:
int data;

template <std::integral T>
constexpr IntTag& operator=(int value) {
data = value;
data = (int)value;
return *this;
}

[[nodiscard]] constexpr operator int() const { return data; } // NOLINT
template <std::integral T>
constexpr operator T() const {
return (T)data;
}

template <std::integral T>
requires(sizeof(T) == 4)
[[nodiscard]] constexpr explicit IntTag(T value = 0) : data((int)value) {}

IntTag operator-() const { return IntTag{(int)-data}; }
Expand Down
5 changes: 2 additions & 3 deletions src/mc/nbt/ListTag.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class ListTag : public ::Tag {
[[nodiscard]] constexpr std::unique_ptr<Tag>& operator[](size_t index) { return mList[index]; }
[[nodiscard]] constexpr std::unique_ptr<Tag> const& operator[](size_t index) const { return mList[index]; }

[[nodiscard]] constexpr size_t size() const { return mList.size(); }

public:
// NOLINTBEGIN
// vIndex: 0, symbol: ??1ListTag@@UEAA@XZ
Expand Down Expand Up @@ -125,8 +127,5 @@ class ListTag : public ::Tag {
// symbol: ?popBack@ListTag@@QEAAXXZ
MCAPI void popBack();

// symbol: ?size@ListTag@@QEBAHXZ
MCAPI int size() const;

// NOLINTEND
};
11 changes: 7 additions & 4 deletions src/mc/nbt/ShortTag.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ class ShortTag : public ::Tag {
public:
short data;

constexpr ShortTag& operator=(short value) {
data = value;
template <std::integral T>
constexpr ShortTag& operator=(T value) {
data = (short)value;
return *this;
}

[[nodiscard]] constexpr operator short() const { return data; } // NOLINT
template <std::integral T>
constexpr operator T() const {
return (T)data;
}

template <std::integral T>
requires(sizeof(T) == 2)
[[nodiscard]] constexpr explicit ShortTag(T value = 0) : data((short)value) {}

ShortTag operator-() const { return ShortTag{(short)-data}; }
Expand Down
49 changes: 30 additions & 19 deletions src/mc/nbt/SnbtDumpImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,39 @@ std::string toDumpString(std::string const& str, fmt::color defaultc, std::strin
std::string res;

bool base64 = false;

bool isTrivial = true;
if (!static_cast<bool>(format & SnbtFormat::Jsonify)) {
for (auto c : str) {
if (!ll::nbt::detail::isTrivialNbtStringChar(c)) {
if (str.empty()) {
res = "\"\"";
} else {
bool isTrivial = true;
if (!static_cast<bool>(format & SnbtFormat::Jsonify)) {
if (str[0] == '-' || isdigit(str[0])) {
isTrivial = false;
break;
} else {
for (auto c : str) {
if (!ll::nbt::detail::isTrivialNbtStringChar(c)) {
isTrivial = false;
break;
}
}
}
} else {
isTrivial = false;
}
} else {
isTrivial = false;
}
if (isTrivial) {
res = str;
} else {
try {
res = nlohmann::json{str}
.dump(-1, ' ', (bool)(format & SnbtFormat::ForceAscii), nlohmann::json::error_handler_t::strict);
res = res.substr(1, res.size() - 2);
} catch (...) {
base64 = true;
res = "\"" + ll::base64::encode(str) + "\"";
if (isTrivial) {
res = str;
} else {
try {
res = nlohmann::json{str}.dump(
-1,
' ',
(bool)(format & SnbtFormat::ForceAscii),
nlohmann::json::error_handler_t::strict
);
res = res.substr(1, res.size() - 2);
} catch (...) {
base64 = true;
res = "\"" + ll::base64::encode(str) + "\"";
}
}
}

Expand Down
Loading

0 comments on commit bb22afd

Please sign in to comment.