CC: Tweaked

CC: Tweaked

65M Downloads

`textutils.unserialiseJSON(s, {nbt_style=true})` does not support all allowed characters for key names

hooded-person opened this issue · 1 comments

commented

Minecraft Version

1.21.1

Version

1.116.0

Details

On CraftOs 1.9
When using textutils.unserialiseJSON(s, {nbt_style=true}) not all valid nbt strings are parsed as valid, some causing errors in textutils.lua instead of returning nil and an error message.
Examples will show the return values of textutils.unserialiseJSON(s, {nbt_style=true}) where s is the value specified in the example.

According to the wiki valid characters for unquoted keys are 0-9, A-Z, a-z, _, -, ., and + however not all of these are parsed correctly:

Completely unsupported

-, . and + are not parsed at all and will cause nil and an error message to be returns
Examples
s = '{entity-name:"james"}' returns nil and Malformed JSON at position 8: Unexpected "-", expected ':'.
s = '{silentlib.SpawnItemsGiven: {}}' returns nil and Malformed JSON at position 11: Unexpected ".", expected ':'.
s = '{bank+wallet: 139}' returns nil and Malformed JSON at position 6: Unexpected "+", expected ':'.

Unsupported at beginning of key

0-9, _, -, ., and + cause errors within textutils.lua when at the beginning of the key. All of the following examples cause the following error:

...rom/apis/textutils.lua:620: attempt to preform arithmetic on local 'last' (a nil value)

(Providing no key also gives this error instead of returning nil and an error message)
Examples
s = '{0of10: true}'
s = '{_broken: 5}'
s = '{-s: true}'
s = '{.james: []}'
s = '{+majo: true}'

Note

All example nbt has been checked and is valid when used in minecraft.

commented

Thanks for the report! Hmrr, looking at the wiki page a bit longer, there's a lot more we get wrong (especially since the changes in 1.21.5). I hadn't realised that strings could always be unquoted (not just in object keys), which means parsing needs to be handled entirely differently1.

I think I'll probably end up spinning this into a new module (cc.strings.snbt), and having the existing textutils.{unserialise,unserialise}JSON functions act as a wrapper around that. At this point, SNBT has diverged pretty significantly from JSON.

It's probably worth mentioning that we'll never be able to parse SNBT perfectly. The new \N{Snowman} sequence would require us to ship all unicode names (or expose it from Java). The aim mostly is to allow parsing the return values from commands (e.g. /data). But that still doesn't mean we shouldn't do as much as possible!

Footnotes

  1. Currently if we see a digit, we assume it's a number. But 12.34.56 is a string! The way to do this is parse everything as a string, and pattern match afterwards.