BenWoodworth / knbt

Kotlin NBT library for kotlinx.serialization
GNU Lesser General Public License v3.0
69 stars 2 forks source link

Allow the encoding/decoding of end tags at root #38

Open WinX64 opened 8 months ago

WinX64 commented 8 months ago

The title pretty much sums it up: Allow the end tag as root to represent an element that is not present, which would allow the serialization of nullable types at root. This is a behavior that already exists on some parts of the Vanilla client/server (item nbts, query responses, among others), so there is an argument in support of making this a more general behavior.

I'm currently using a workaround to make it possible. But it's quite hacky to have to do this from outside the library, since it involves having to read ahead and then rolling back depending on the type of tag.

BenWoodworth commented 8 months ago

Sounds straightforward enough. On JavaNetwork (and BedrockNetwork?) a single 0 byte will be serialized, and the other variants will fail with something like "expected TAG_Compound, but got TAG_End"?

Can you confirm I've got that right for the new/old Java protocol, and for bedrock's protocol. No name bytes encoded at all for any of them

WinX64 commented 8 months ago

Yes, that is it. When the nbt data starts with a 0 (tag end), nothing follows. That has been the behavior before and after the removal of root tag names on Java, though I can't say if this was ever a thing on the Bedrock side of things.

I imagine it could generally be implemented as:

val nullableCompound: NbtCompound? = nbt.decodeFromStream(input)
nbt.encodeToStream(nullableCompound, output)

It would also fail if encountering a tag end when deserializing a non-nullable type, same as with Json.