Skip to content

Commit

Permalink
BlockTypePalette: Load from TSV or original reports' JSON.
Browse files Browse the repository at this point in the history
  • Loading branch information
madmaxoft committed Dec 28, 2019
1 parent a9fadde commit e276988
Show file tree
Hide file tree
Showing 14 changed files with 21,087 additions and 384 deletions.
1 change: 0 additions & 1 deletion Server/Protocol/1.13/base.btp.json

This file was deleted.

8,586 changes: 8,586 additions & 0 deletions Server/Protocol/1.13/base.btp.txt

Large diffs are not rendered by default.

11,275 changes: 11,275 additions & 0 deletions Server/Protocol/1.14.4/base.btp.txt

Large diffs are not rendered by default.

554 changes: 554 additions & 0 deletions Server/Protocol/UpgradeBlockTypePalette.txt

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Tools/BlockTypePaletteGenerator/.gitignore
@@ -0,0 +1,5 @@
# Ignore the scripts' outputs:
*.json
*.btp.txt
UpgradeBlockTypePalette.txt

180 changes: 127 additions & 53 deletions Tools/BlockTypePaletteGenerator/Generator.lua
@@ -1,14 +1,33 @@
-- lib/lunajson/src/ is not in default Lua package paths
-- Generator.lua

--[[
Crafts an intermediate block palette format to be read by Cuberite.
It processes the blocks.json report file (https://wiki.vg/Data_Generators)
into a file that can be loaded into a BlockTypePalette (and is to be stored
as Server/Protocol/<version>/base.btp.txt).
The output format is the regular TSV BlockTypePalette, described in the
$/src/BlockTypePalette.h file.
--]]
-- Allow Lua to load libraries in our subfolder:
package.path = 'lib/lunajson/src/?.lua;' .. package.path;
--- Prints usage instructions to stdout.
-- If the optional `message` is passed, output is prepended by message _and_
-- If the optional `aMessage` is passed, output is prepended by message _and_
-- redirected to stderr.
function usage(message)
if message then
local function usage(aMessage)
if aMessage then
io.output(io.stderr);
io.write(message, "\n\n");
io.write(aMessage, "\n\n");
end
io.write(
"Usage: lua Generator.lua INPUTFILE OUTPUTFILE\n"..
Expand All @@ -22,70 +41,125 @@ function usage(message)
end
-- Test whether the script is run in a path where it can load it's libraries
if not pcall(function() require("lunajson.decoder") end) then
usage("Could not load required libraries, please run `Generator.lua` "..
"within its directory and make sure to run `git submodule update`.");
end
-- Check/Prepare CLI arguments
local inpath, outpath = ...;
io.input(io.stdin);
io.output(io.stdout);
if select("#", ...) ~= 2 then
usage("Incorrect number of arguments.");
--- Parses the JSON registry into a Lua table
--[[ The returned array-table has the following format:
{
{ id = 1, blockTypeName = "minecraft:stone", properties = {key = value, ...} },
...
}
--]]
local function parseRegistry(aBlockRegistryJsonStr)
assert(type(aBlockRegistryJsonStr) == "string")
local lj = require("lunajson")
local input = lj.decode(aBlockRegistryJsonStr)
local registry = {}
local idx = 1
for blockTypeName, blockData in pairs(input) do
for _, state in pairs(blockData.states) do
registry[idx] = {
id = state.id,
blockTypeName = blockTypeName,
properties = state.properties,
}
idx = idx + 1
end
end
return registry
end
if inpath ~= "-" then
local handle, err = io.open(inpath, "r");
io.input(handle or usage(err));
end
if outpath ~= "-" then
local handle, err = io.open(outpath, "w");
io.output(handle or usage(err));
end
-- Main program starts here
local decode = (require("lunajson.decoder"))();
local encode = (require("lunajson.encoder"))();
local input = decode(io.input():read("*a"));
local registry = {};
local max_id = -1;
--- Serializes the properties from the JSON / array table format into a single output string
-- Concatenates all properties with \t as the delimiting character
local function serializeProperties(aProperties)
local res = {}
local idx = 1
for k, v in pairs(aProperties or {}) do
res[idx] = k
res[idx + 1] = v
idx = idx + 2
end
return table.concat(res, "\t")
end
for blockname, blockdata in pairs(input) do
for i = 1, #(blockdata.states or {}) do
local state = blockdata.states[i];
assert(registry[state.id + 1] == nil, "Ensure no duplicate IDs");
-- needed in the end to verify we got no holes in the array:
max_id = math.max(max_id, state.id);
registry[state.id + 1] = {
id = assert(state.id, "id is required."),
name = assert(blockname, "Block type name is required."),
-- default = state.default or nil, -- may need this later
props = state.properties,
};
--- Returns the prefix that is common for all block type names in the registry
-- aRegistry is the parsed registry, as returned from parseRegistry()
local function findCommonPrefix(aRegistryTable)
local prefix = aRegistryTable[1].blockTypeName
local len = string.len(prefix)
local sub = string.sub
for _, block in ipairs(aRegistryTable) do
while (sub(block.blockTypeName, 1, len) ~= prefix) do
len = len - 1
if (len == 0) then
return ""
end
prefix = sub(prefix, 1, len)
end
end
return prefix
end
-- The following assertion is not necessary by the current spec, but is required
-- by how lunajson distinguishes objects from arrays. Also if this fails, it is
-- _very_ likely that the input file is faulty.
assert(#registry == max_id + 1, "Ensure that registry has contiguous keys");
local out = {
Metadata = {
ProtocolBlockTypePaletteVersion = 1
},
Palette = registry
};
io.write(encode(out), "\n");
-- Test whether the script is run in a path where it can load it's libraries
if not(pcall(function() require("lunajson") end)) then
usage(
"Could not load required libraries, please run `Generator.lua` " ..
"within its directory and make sure to run `git submodule update`."
)
end
-- Check/Prepare CLI arguments
local inpath, outpath = ...;
inpath = inpath or "blocks.json"
outpath = outpath or "base.btp.txt"
if (inpath ~= "-") then
local handle, err = io.open(inpath, "r")
io.input(handle or usage(err))
end
if (outpath ~= "-") then
local handle, err = io.open(outpath, "w")
io.output(handle or usage(err))
end
-- Parse the registry:
local registry = parseRegistry(io.input():read("*a"))
local commonPrefix = findCommonPrefix(registry)
-- Sort the entries:
table.sort(registry,
function (entry1, entry2)
return (entry1.id < entry2.id)
end
)
-- Write out the output format:
io.write("BlockTypePalette\n")
io.write("FileVersion\t1\n")
io.write("CommonPrefix\t", commonPrefix, "\n")
io.write("\n")
local prefixLen = string.len(commonPrefix) + 1
for _, entry in ipairs(registry) do
local props = serializeProperties(entry.properties)
if (props ~= "") then
props = "\t" .. props
end
io.write(
entry.id, "\t",
string.sub(entry.blockTypeName, prefixLen),
props, "\n"
)
end
63 changes: 0 additions & 63 deletions Tools/BlockTypePaletteGenerator/Readme.md

This file was deleted.

0 comments on commit e276988

Please sign in to comment.