1
0
Fork 0
cuberite-2a/Tools/BlockTypePaletteGenerator/UpgradeGenerator.lua

224 lines
5.7 KiB
Lua

-- UpgradeGenerator.lua
--[[ Creates the UpgradeBlockTypePalette out of JSON data of the Minutor project
(https://github.com/mrkite/minutor/blob/master/definitions/vanilla_ids.json
Parses the JSON into memory, then walks each block's "id" member and possibly
the "variants" sub-member to read the block types. The name is either present as "flatname",
or is synthesized from the internal Minutor "name" by lowercasing and replacing spaces
with underscores.
Expects two parameters, the input file and output file; either can be replaced by
a "-" to use stdin / stdout instead. If not given, the input file defaults to
"vanilla_ids.json" and the output file defaults to "UpgradeBlockTypePalette.txt"
The output format is the upgrade 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;
--- Splits the full flat name into flat name and properties
-- "minecraft:carrots:age:0" -> "minecraft:carrots", {age = 0}
local function splitFlatName(aFullFlatName)
local props = {}
local numParts = 0
local flatName = ""
local propKey = ""
aFullFlatName:gsub("([^:]+)",
function (aPart)
if (numParts == 0) then
flatName = aPart
elseif (numParts == 1) then
flatName = flatName .. ":" .. aPart
elseif (numParts % 2 == 0) then
propKey = aPart
else
props[propKey] = aPart
end
numParts = numParts + 1
end
)
return flatName, props
end
--- Returns the minecraft block name, created from the flat name if present, or synthesized
-- from the Minutor name
-- If the flat name contains encoded block properties, it returns those properties as a dict-table
-- in the second return value
local function processBlockName(aFlatName, aMinutorName)
if (aFlatName) then
assert(type(aFlatName) == "string")
return splitFlatName(aFlatName)
end
if not(type(aMinutorName) == "string") then
return nil
end
return "minecraft:" .. (aMinutorName:lower():gsub(" ", "_")), {}
end
--- 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
--- Parses the vanilla_ids.json into a common registry format
-- The returned registry is an array-table of
-- {blockType = 1, blockMeta = 2, blockTypeName = "name", properties = {key = value, ...}}
local function parseRegistry(aJsonString)
assert(type(aJsonString) == "string")
-- Parse the JSON:
local lj = require("lunajson")
local input = lj.decode(aJsonString)
if (not(input) or (input["type"] ~= "block") or not(input["data"])) then
error("The input file doesn't contain vanilla IDs.")
end
-- Create the registry:
local registry = {}
local idx = 1
for _, entry in pairs(input["data"]) do
local id = entry["id"]
local parentBlockTypeName, props = processBlockName(entry["flatname"], entry["name"])
registry[idx] =
{
blockType = id,
blockMeta = 0,
blockTypeName = parentBlockTypeName,
properties = props,
}
idx = idx + 1
for _, variant in pairs(entry["variants"] or {}) do
local blockTypeName, props = processBlockName(variant["flatname"], variant["name"])
if not(blockTypeName) then
-- Some blocks don't have all their variants named ("brown mushroom block"), use the parent name in such a case
blockTypeName = parentBlockTypeName
end
registry[idx] =
{
blockType = id,
blockMeta = variant["data"],
blockTypeName = blockTypeName,
properties = props,
}
idx = idx + 1
end
end
return registry
end
--- 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
-- Test whether the script is run in a path where it can load it's libraries
if not(pcall(function() require("lunajson") end)) then
error(
"Could not load required libraries, please run `UpgradeGenerator.lua` " ..
"within its directory and make sure to run `git submodule update`."
)
end
-- Check/Prepare CLI arguments
local inpath, outpath = ...;
inpath = inpath or "vanilla_ids.json"
outpath = outpath or "UpgradeBlockTypePalette.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)
if (entry1.blockType < entry2.blockType) then
return true
elseif (entry1.blockType > entry2.blockType) then
return false
else
return (entry1.blockMeta < entry2.blockMeta)
end
end
)
-- Write out the output format:
io.write("UpgradeBlockTypePalette\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.blockType, "\t", entry.blockMeta, "\t",
string.sub(entry.blockTypeName, prefixLen),
props, "\n"
)
end