All programming problems should be solved by a good night's sleep
To sum things up:
Vanilla network protocol uses a so-called global palette, which is fixed for the specific Minecraft version, both the server and the client have a copy of the palette, so it's not sent through the protocol at all. In disk-stored chunks, the block states are stored in full (map of key -> value) and translated into that palette in-memory when loaded. The server executable is capable of outputting the global palette into a json file (
https://wiki.vg/Data_Generators#Blocks_report ).
I think here's what we should do:
1. Allow any combination of block type name and block state in the world, and support storing it in the saved world.
2. Each 1.13+ vanilla protocol (each separate sub-version, like 1.13.1, 1.13.2 etc.) should read the block report file and use it as the global palette, translating the internal representation to the version-specific network representation. Any unknown block / blockstate should be replaced with some reasonable placeholder (air? bedrock?)
3. (legal: ) Can we distribute the vanilla-generated block report file, or will we need to instruct the users to generate their own and feed it to Cuberite?
4. Cuberite should support dynamic block registration and unregistration by plugins
5. At first we should focus on the minimum amount of code changes that support the 1.13 flattening; even if it means a performance drop at first.
For this reason, I still think implementing a global palette as the first step is not a good idea, especially considering the potential dynamic block registry. It can wait for later, if it is deemed reasonable.