|
|
@@ -10,6 +10,9 @@ namespace YumeBot::Jce
|
|
|
DeclareException(JceDecodeException, JceException, u8"YumeBot::Jce::JceDecodeException");
|
|
|
DeclareException(JceEncodeException, JceException, u8"YumeBot::Jce::JceEncodeException");
|
|
|
|
|
|
+ static_assert(std::numeric_limits<float>::is_iec559 && std::numeric_limits<double>::is_iec559, "Jce assumed float and double fulfill the requirements of IEEE 754(IEC 559) standard.");
|
|
|
+ static_assert(nString::UsingStringType == NatsuLib::StringType::Utf8, "Encoding should be utf-8.");
|
|
|
+
|
|
|
// Jce 中 Byte 是有符号的,此处表示为无符号,使用时需注意
|
|
|
class JceStruct
|
|
|
: public NatsuLib::natRefObj
|
|
|
@@ -22,8 +25,8 @@ namespace YumeBot::Jce
|
|
|
OP(Long, 0x03, std::int64_t)\
|
|
|
OP(Float, 0x04, float)\
|
|
|
OP(Double, 0x05, double)\
|
|
|
- OP(String1, 0x06, std::string)\
|
|
|
- OP(String4, 0x07, std::string)\
|
|
|
+ OP(String1, 0x06, nString)\
|
|
|
+ OP(String4, 0x07, nString)\
|
|
|
OP(Map, 0x08, std::unordered_map)\
|
|
|
OP(List, 0x09, std::vector)\
|
|
|
OP(StructBegin, 0x0A, NatsuLib::natRefPointer)\
|
|
|
@@ -57,7 +60,7 @@ namespace YumeBot::Jce
|
|
|
|
|
|
~JceStruct();
|
|
|
|
|
|
- virtual nStrView GetJceStructName() const noexcept = 0;
|
|
|
+ [[nodiscard]] virtual nStrView GetJceStructName() const noexcept = 0;
|
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
|
@@ -88,161 +91,17 @@ namespace YumeBot::Jce
|
|
|
explicit JceInputStream(NatsuLib::natRefPointer<NatsuLib::natBinaryReader> reader);
|
|
|
~JceInputStream();
|
|
|
|
|
|
- std::pair<HeadData, std::size_t> ReadHead() const
|
|
|
- {
|
|
|
- const auto byte = m_Reader->ReadPod<std::uint8_t>();
|
|
|
- const auto type = static_cast<JceStruct::TypeEnum>(static_cast<std::uint8_t>(byte & 0x0F));
|
|
|
- const auto tag = static_cast<std::uint32_t>((byte & 0xF0) >> 4);
|
|
|
-
|
|
|
- if (tag != 0x0F)
|
|
|
- {
|
|
|
- return { { tag, type }, 1 };
|
|
|
- }
|
|
|
-
|
|
|
- return { { m_Reader->ReadPod<std::uint8_t>(), type }, 2 };
|
|
|
- }
|
|
|
-
|
|
|
- std::pair<HeadData, std::size_t> PeekHead() const
|
|
|
- {
|
|
|
- const auto underlyingStream = m_Reader->GetUnderlyingStream();
|
|
|
- const auto pos = underlyingStream->GetPosition();
|
|
|
- const auto head = ReadHead();
|
|
|
- underlyingStream->SetPositionFromBegin(pos);
|
|
|
- return head;
|
|
|
- }
|
|
|
-
|
|
|
- void Skip(nLen len)
|
|
|
- {
|
|
|
- m_Reader->Skip(len);
|
|
|
- }
|
|
|
-
|
|
|
- void SkipToStructEnd()
|
|
|
- {
|
|
|
- while (true)
|
|
|
- {
|
|
|
- const auto [head, headSize] = ReadHead();
|
|
|
- SkipField(head.Type);
|
|
|
- if (head.Type == JceStruct::TypeEnum::StructEnd)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void SkipField()
|
|
|
- {
|
|
|
- const auto [head, headSize] = ReadHead();
|
|
|
- SkipField(head.Type);
|
|
|
- }
|
|
|
-
|
|
|
- void SkipField(JceStruct::TypeEnum type)
|
|
|
- {
|
|
|
- switch (type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::Byte:
|
|
|
- Skip(1);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Short:
|
|
|
- Skip(2);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Int:
|
|
|
- Skip(4);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Long:
|
|
|
- Skip(8);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Float:
|
|
|
- Skip(4);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Double:
|
|
|
- Skip(8);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::String1:
|
|
|
- Skip(m_Reader->ReadPod<std::uint8_t>());
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::String4:
|
|
|
- Skip(m_Reader->ReadPod<std::uint32_t>());
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Map:
|
|
|
- {
|
|
|
- int size;
|
|
|
- if (!Read(0, size))
|
|
|
- {
|
|
|
- nat_Throw(JceDecodeException, u8"Read size failed.");
|
|
|
- }
|
|
|
- for (std::size_t i = 0, iterationTime = static_cast<std::size_t>(size) * 2; i < iterationTime; ++i)
|
|
|
- {
|
|
|
- SkipField();
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case JceStruct::TypeEnum::List:
|
|
|
- {
|
|
|
- int size;
|
|
|
- if (!Read(0, size))
|
|
|
- {
|
|
|
- nat_Throw(JceDecodeException, u8"Read size failed.");
|
|
|
- }
|
|
|
- for (std::size_t i = 0, iterationTime = static_cast<std::size_t>(size); i < iterationTime; ++i)
|
|
|
- {
|
|
|
- SkipField();
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case JceStruct::TypeEnum::StructBegin:
|
|
|
- SkipToStructEnd();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::StructEnd:
|
|
|
- case JceStruct::TypeEnum::ZeroTag:
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::SimpleList:
|
|
|
- {
|
|
|
- const auto [head, headSize] = ReadHead();
|
|
|
- if (head.Type != JceStruct::TypeEnum::Byte)
|
|
|
- {
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, expected 0, got {0}", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
- std::uint8_t size;
|
|
|
- if (!Read(0, size))
|
|
|
- {
|
|
|
- nat_Throw(JceDecodeException, u8"Read size failed.");
|
|
|
- }
|
|
|
- Skip(size);
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Invalid type ({0}).", static_cast<std::uint32_t>(type));
|
|
|
- }
|
|
|
- }
|
|
|
+ std::pair<HeadData, std::size_t> ReadHead() const;
|
|
|
+ std::pair<HeadData, std::size_t> PeekHead() const;
|
|
|
|
|
|
- bool SkipToTag(std::uint32_t tag)
|
|
|
- try
|
|
|
- {
|
|
|
- HeadData head; // NOLINT
|
|
|
- while (true)
|
|
|
- {
|
|
|
- std::size_t headSize;
|
|
|
- std::tie(head, headSize) = PeekHead();
|
|
|
- if (head.Type == JceStruct::TypeEnum::StructEnd)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (tag <= head.Tag)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- Skip(headSize);
|
|
|
- SkipField(head.Type);
|
|
|
- }
|
|
|
- return head.Tag == tag;
|
|
|
- }
|
|
|
- catch (JceDecodeException&)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ void Skip(nLen len);
|
|
|
+ void SkipToStructEnd();
|
|
|
+ void SkipField();
|
|
|
+ void SkipField(JceStruct::TypeEnum type);
|
|
|
+ bool SkipToTag(std::uint32_t tag);
|
|
|
|
|
|
template <typename T>
|
|
|
- bool Read(std::uint32_t tag, T& value, Detail::NoneType = Detail::None)
|
|
|
+ [[nodiscard]] bool Read(std::uint32_t tag, T& value, Detail::NoneType = Detail::None)
|
|
|
{
|
|
|
return doRead(tag, value);
|
|
|
}
|
|
|
@@ -272,197 +131,13 @@ namespace YumeBot::Jce
|
|
|
private:
|
|
|
NatsuLib::natRefPointer<NatsuLib::natBinaryReader> m_Reader;
|
|
|
|
|
|
- bool doRead(std::uint32_t tag, std::uint8_t& value)
|
|
|
- {
|
|
|
- if (SkipToTag(tag))
|
|
|
- {
|
|
|
- const auto[head, headSize] = ReadHead();
|
|
|
- switch (head.Type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::Byte:
|
|
|
- m_Reader->ReadPod(value);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::ZeroTag:
|
|
|
- value = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}.", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- bool doRead(std::uint32_t tag, std::int16_t& value)
|
|
|
- {
|
|
|
- if (SkipToTag(tag))
|
|
|
- {
|
|
|
- const auto[head, headSize] = ReadHead();
|
|
|
- switch (head.Type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::Byte:
|
|
|
- value = m_Reader->ReadPod<std::int8_t>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Short:
|
|
|
- m_Reader->ReadPod(value);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::ZeroTag:
|
|
|
- value = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}.", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- bool doRead(std::uint32_t tag, std::int32_t& value)
|
|
|
- {
|
|
|
- if (SkipToTag(tag))
|
|
|
- {
|
|
|
- const auto[head, headSize] = ReadHead();
|
|
|
- switch (head.Type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::Byte:
|
|
|
- value = m_Reader->ReadPod<std::int8_t>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Short:
|
|
|
- value = m_Reader->ReadPod<std::int16_t>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Int:
|
|
|
- m_Reader->ReadPod(value);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::ZeroTag:
|
|
|
- value = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}.", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- bool doRead(std::uint32_t tag, std::int64_t& value)
|
|
|
- {
|
|
|
- if (SkipToTag(tag))
|
|
|
- {
|
|
|
- const auto[head, headSize] = ReadHead();
|
|
|
- switch (head.Type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::Byte:
|
|
|
- value = m_Reader->ReadPod<std::int8_t>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Short:
|
|
|
- value = m_Reader->ReadPod<std::int16_t>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Int:
|
|
|
- value = m_Reader->ReadPod<std::int32_t>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Long:
|
|
|
- m_Reader->ReadPod(value);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::ZeroTag:
|
|
|
- value = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected got {0}", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- bool doRead(std::uint32_t tag, float& value)
|
|
|
- {
|
|
|
- if (SkipToTag(tag))
|
|
|
- {
|
|
|
- const auto[head, headSize] = ReadHead();
|
|
|
- switch (head.Type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::Float:
|
|
|
- m_Reader->ReadPod(value);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::ZeroTag:
|
|
|
- value = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}.", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- bool doRead(std::uint32_t tag, double& value)
|
|
|
- {
|
|
|
- if (SkipToTag(tag))
|
|
|
- {
|
|
|
- const auto[head, headSize] = ReadHead();
|
|
|
- switch (head.Type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::Float:
|
|
|
- value = m_Reader->ReadPod<float>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::Double:
|
|
|
- m_Reader->ReadPod(value);
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::ZeroTag:
|
|
|
- value = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}.", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- bool doRead(std::uint32_t tag, std::string& value)
|
|
|
- {
|
|
|
- if (SkipToTag(tag))
|
|
|
- {
|
|
|
- const auto[head, headSize] = ReadHead();
|
|
|
- std::size_t strSize;
|
|
|
- switch (head.Type)
|
|
|
- {
|
|
|
- case JceStruct::TypeEnum::String1:
|
|
|
- strSize = m_Reader->ReadPod<std::uint8_t>();
|
|
|
- break;
|
|
|
- case JceStruct::TypeEnum::String4:
|
|
|
- strSize = m_Reader->ReadPod<std::uint32_t>();
|
|
|
- if (strSize > JceStruct::MaxStringLength)
|
|
|
- {
|
|
|
- nat_Throw(JceDecodeException, u8"String too long, {0} sizes requested.", strSize);
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}.", static_cast<std::uint32_t>(head.Type));
|
|
|
- }
|
|
|
-
|
|
|
- // 为了异常安全,构造临时字符串而不是就地修改
|
|
|
- std::string tmpString(strSize, 0);
|
|
|
- m_Reader->GetUnderlyingStream()->ReadBytes(reinterpret_cast<nData>(tmpString.data()), strSize);
|
|
|
- value = std::move(tmpString);
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
+ bool doRead(std::uint32_t tag, std::uint8_t& value);
|
|
|
+ bool doRead(std::uint32_t tag, std::int16_t& value);
|
|
|
+ bool doRead(std::uint32_t tag, std::int32_t& value);
|
|
|
+ bool doRead(std::uint32_t tag, std::int64_t& value);
|
|
|
+ bool doRead(std::uint32_t tag, float& value);
|
|
|
+ bool doRead(std::uint32_t tag, double& value);
|
|
|
+ bool doRead(std::uint32_t tag, nString& value);
|
|
|
|
|
|
template <typename Key, typename Value>
|
|
|
bool doRead(std::uint32_t tag, std::unordered_map<Key, Value>& value)
|
|
|
@@ -616,27 +291,9 @@ namespace YumeBot::Jce
|
|
|
explicit JceOutputStream(NatsuLib::natRefPointer<NatsuLib::natBinaryWriter> writer);
|
|
|
~JceOutputStream();
|
|
|
|
|
|
- NatsuLib::natRefPointer<NatsuLib::natBinaryWriter> GetWriter() const noexcept
|
|
|
- {
|
|
|
- return m_Writer;
|
|
|
- }
|
|
|
+ [[nodiscard]] NatsuLib::natRefPointer<NatsuLib::natBinaryWriter> GetWriter() const noexcept;
|
|
|
|
|
|
- void WriteHead(HeadData head)
|
|
|
- {
|
|
|
- if (head.Tag < 15)
|
|
|
- {
|
|
|
- m_Writer->WritePod(static_cast<std::uint8_t>((head.Tag << 4) | static_cast<std::uint8_t>(head.Type)));
|
|
|
- }
|
|
|
- else if (head.Tag < 256)
|
|
|
- {
|
|
|
- m_Writer->WritePod(static_cast<std::uint8_t>(static_cast<std::uint8_t>(head.Type) | 0xF0));
|
|
|
- m_Writer->WritePod(static_cast<std::uint8_t>(head.Tag));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- nat_Throw(JceEncodeException, u8"Tag is too big({0}).", head.Tag);
|
|
|
- }
|
|
|
- }
|
|
|
+ void WriteHead(HeadData head);
|
|
|
|
|
|
template <typename T>
|
|
|
void Write(std::uint32_t tag, T const& value)
|
|
|
@@ -665,90 +322,14 @@ namespace YumeBot::Jce
|
|
|
private:
|
|
|
NatsuLib::natRefPointer<NatsuLib::natBinaryWriter> m_Writer;
|
|
|
|
|
|
- void doWrite(std::uint32_t tag, std::uint8_t value)
|
|
|
- {
|
|
|
- if (!value)
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::ZeroTag });
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::Byte });
|
|
|
- m_Writer->WritePod(value);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void doWrite(std::uint32_t tag, std::int16_t value)
|
|
|
- {
|
|
|
- if (Utility::InRangeOf<std::int8_t>(value))
|
|
|
- {
|
|
|
- Write(tag, static_cast<std::uint8_t>(value));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::Short });
|
|
|
- m_Writer->WritePod(value);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void doWrite(std::uint32_t tag, std::int32_t value)
|
|
|
- {
|
|
|
- if (Utility::InRangeOf<std::int16_t>(value))
|
|
|
- {
|
|
|
- Write(tag, static_cast<std::int16_t>(value));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::Int });
|
|
|
- m_Writer->WritePod(value);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void doWrite(std::uint32_t tag, std::int64_t value)
|
|
|
- {
|
|
|
- if (Utility::InRangeOf<std::int32_t>(value))
|
|
|
- {
|
|
|
- Write(tag, static_cast<std::int32_t>(value));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::Long });
|
|
|
- m_Writer->WritePod(value);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void doWrite(std::uint32_t tag, float value)
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::Float });
|
|
|
- m_Writer->WritePod(value);
|
|
|
- }
|
|
|
-
|
|
|
- void doWrite(std::uint32_t tag, double value)
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::Double });
|
|
|
- m_Writer->WritePod(value);
|
|
|
- }
|
|
|
-
|
|
|
- void doWrite(std::uint32_t tag, std::string const& value)
|
|
|
- {
|
|
|
- const auto strSize = value.size();
|
|
|
- if (strSize <= std::numeric_limits<std::uint8_t>::max())
|
|
|
- {
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::String1 });
|
|
|
- m_Writer->WritePod(static_cast<std::uint8_t>(strSize));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (strSize > std::numeric_limits<std::uint32_t>::max())
|
|
|
- {
|
|
|
- nat_Throw(JceDecodeException, u8"String is too long({0} bytes).", strSize);
|
|
|
- }
|
|
|
-
|
|
|
- WriteHead({ tag, JceStruct::TypeEnum::String4 });
|
|
|
- m_Writer->WritePod(static_cast<std::uint32_t>(strSize));
|
|
|
- }
|
|
|
- m_Writer->GetUnderlyingStream()->WriteBytes(reinterpret_cast<ncData>(value.data()), strSize);
|
|
|
- }
|
|
|
+ void doWrite(std::uint32_t tag, std::uint8_t value);
|
|
|
+ void doWrite(std::uint32_t tag, std::int16_t value);
|
|
|
+ void doWrite(std::uint32_t tag, std::int32_t value);
|
|
|
+ void doWrite(std::uint32_t tag, std::int64_t value);
|
|
|
+ void doWrite(std::uint32_t tag, float value);
|
|
|
+ void doWrite(std::uint32_t tag, double value);
|
|
|
+ void doWrite(std::uint32_t tag, nStrView const& value);
|
|
|
+ void doWrite(std::uint32_t tag, nString const& value);
|
|
|
|
|
|
template <typename Key, typename Value>
|
|
|
void doWrite(std::uint32_t tag, std::unordered_map<Key, Value> const& value)
|
|
|
@@ -762,6 +343,8 @@ namespace YumeBot::Jce
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ void doWrite(std::uint32_t tag, std::vector<std::uint8_t> const& value);
|
|
|
+
|
|
|
template <typename T>
|
|
|
void doWrite(std::uint32_t tag, std::vector<T> const& value)
|
|
|
{
|
|
|
@@ -856,7 +439,7 @@ namespace YumeBot::Jce
|
|
|
return tag;\
|
|
|
}
|
|
|
|
|
|
-#define JCE_STRUCT(name) \
|
|
|
+#define JCE_STRUCT(name, alias) \
|
|
|
class name\
|
|
|
: public NatsuLib::natRefObjImpl<name, JceStruct>\
|
|
|
{\
|
|
|
@@ -887,7 +470,7 @@ namespace YumeBot::Jce
|
|
|
}\
|
|
|
}
|
|
|
|
|
|
-#define JCE_STRUCT(name) \
|
|
|
+#define JCE_STRUCT(name, alias) \
|
|
|
template <>\
|
|
|
struct JceDeserializer<name>\
|
|
|
{\
|
|
|
@@ -905,7 +488,7 @@ namespace YumeBot::Jce
|
|
|
|
|
|
#define FIELD(name, tag, type, ...) stream.Write(tag, value->Get##name());
|
|
|
|
|
|
-#define JCE_STRUCT(name) \
|
|
|
+#define JCE_STRUCT(name, alias) \
|
|
|
template <>\
|
|
|
struct JceSerializer<name>\
|
|
|
{\
|