forked from cuberite/cuberite
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ProtocolBlockTypePalette (cuberite#4391)
- Loading branch information
Showing
15 changed files
with
815 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
-- lib/lunajson/src/ is not in default Lua package paths | ||
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_ | ||
-- redirected to stderr. | ||
function usage(message) | ||
if message then | ||
io.output(io.stderr); | ||
io.write(message, "\n\n"); | ||
end | ||
io.write( | ||
"Usage: lua Generator.lua INPUTFILE OUTPUTFILE\n".. | ||
"Converts the Minecraft blocks.json report format to the cuberite ".. | ||
"block type palette format.\n".. | ||
"\n".. | ||
"INPUTFILE and OUTPUTFILE must point to a valid path. INPUTFILE must ".. | ||
"be readable and OUTPUTFILE must be writable. Either can be replaced ".. | ||
"with `-` (dash character) to point to standard-input or -output.\n"); | ||
os.exit(message and 1 or 0); | ||
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."); | ||
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; | ||
|
||
|
||
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, | ||
}; | ||
end | ||
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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
This generator crafts an intermediate index format to be read by cuberite | ||
|
||
# Running | ||
|
||
Run `lua ./Generator.lua`, pass `blocks.json` as first argument to the script | ||
and the desired output location as 2nd argument. | ||
|
||
Make sure to run the Generator from within its directory (`cd` into the path | ||
where `Generator.lua` is.) | ||
|
||
## Examples | ||
|
||
```bash | ||
SERVER=/path/to/server.jar | ||
java -cp "$SERVER" net.minecraft.data.Main --reports && | ||
lua Generator.lua \ | ||
generated/reports/blocks.json \ | ||
../../Server/Protocol/1.13/ProtocolBlockTypePalette.json | ||
``` | ||
|
||
```bash | ||
SERVER=/path/to/server.jar | ||
java -cp "$SERVER" net.minecraft.data.Main --reports && | ||
lua Generator.lua - -\ | ||
< generated/reports/blocks.json \ | ||
> ../Server/Protocol/1.13/ProtocolBlockTypePalette.json | ||
``` | ||
|
||
## Output format | ||
|
||
The Format is a `JSON` document containing an object with at least two keys at | ||
the top level: `Metadata` and `Palette`. | ||
|
||
`Metadata` contains document metadata, namely a key `"ProtocolBlockType": 1`. | ||
|
||
`Palette` contains an array of objects. Each of these objects has at least the | ||
keys `id`, `name` and an optional `props` key that contains the individual | ||
properties of the current state. These properties are a KV dict of pure strings. | ||
|
||
The order of the array or object elements is not significant. `id` is unique. | ||
|
||
```json | ||
{ | ||
"Metadata": { | ||
"ProtocolBlockType": 1 | ||
}, | ||
"Palette": [{ | ||
"id": 0, | ||
"name": "minecraft:air" | ||
}, { | ||
"id": 1, | ||
"name": "minecraft:stone" | ||
}, { | ||
"id": 221, | ||
"name": "minecraft:dark_oak_leaves", | ||
"props": { | ||
"persistent": "false", | ||
"distance": "4" | ||
} | ||
} | ||
] | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
#include "Globals.h" | ||
#include "ProtocolBlockTypePalette.h" | ||
#include <cstdint> | ||
#include <sstream> | ||
#include "json/value.h" | ||
#include "json/reader.h" | ||
|
||
|
||
|
||
|
||
|
||
ProtocolBlockTypePalette::ProtocolBlockTypePalette() | ||
{ | ||
// empty | ||
} | ||
|
||
|
||
|
||
|
||
|
||
bool ProtocolBlockTypePalette::loadFromString(const AString & aMapping) | ||
{ | ||
std::stringstream stream; | ||
stream << aMapping; | ||
|
||
return loadFromStream(stream); | ||
} | ||
|
||
|
||
|
||
|
||
|
||
bool ProtocolBlockTypePalette::loadFromStream(std::istream & aInputStream) | ||
{ | ||
Json::Value root; | ||
|
||
try | ||
{ | ||
aInputStream >> root; | ||
} | ||
#if defined _DEBUG | ||
catch (const std::exception & e) | ||
{ | ||
LOGD(e.what()); | ||
return false; | ||
} | ||
#else | ||
catch (const std::exception &) | ||
{ | ||
return false; | ||
} | ||
#endif | ||
|
||
if (!root.isObject() || | ||
!root.isMember("Metadata") || | ||
!root["Metadata"].isMember("ProtocolBlockTypePaletteVersion") || | ||
!root.isMember("Palette") || | ||
!root["Palette"].isArray()) | ||
{ | ||
LOGD("Incorrect palette format."); | ||
return false; | ||
} | ||
|
||
if (root["Metadata"]["ProtocolBlockTypePaletteVersion"].asUInt() != 1) | ||
{ | ||
LOGD("Palette format version not supported."); | ||
return false; | ||
} | ||
|
||
auto len = root["Palette"].size(); | ||
for (decltype(len) i = 0; i < len; ++i) | ||
{ | ||
const auto & record = root["Palette"][i]; | ||
if (!record.isObject()) | ||
{ | ||
LOGD("Record #%u must be a JSON object.", i); | ||
return false; | ||
} | ||
|
||
auto blocktype = record["name"].asString(); | ||
auto id = std::stoul(record["id"].asString()); | ||
std::map<AString, AString> state; | ||
|
||
if (id >= NOT_FOUND) | ||
{ | ||
LOGD("`id` must be less than ProtocolBlockTypePalette::NOT_FOUND, but is %lu", id); | ||
return false; | ||
} | ||
|
||
if (record.isMember("props")) | ||
{ | ||
const auto & props = record["props"]; | ||
if (!props.isObject()) | ||
{ | ||
LOGD("`props` key must be a JSON object."); | ||
return false; | ||
} | ||
for (const auto & key: props.getMemberNames()) | ||
{ | ||
state[key] = props[key].asString(); | ||
} | ||
} | ||
|
||
// Block type map entry already exists? | ||
if (mIndex.count(blocktype) == 0) | ||
{ | ||
mIndex.insert({blocktype, std::map<BlockState, UInt32>()}); | ||
} | ||
|
||
const auto & result = mIndex[blocktype].insert({BlockState(state), id}); | ||
if (result.second == false) | ||
{ | ||
LOGINFO("Duplicate block state encountered (Current ID: %lu, other: %lu)", result.first->second, id); | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
|
||
|
||
|
||
|
||
UInt32 ProtocolBlockTypePalette::index(const AString & aBlockTypeName, const BlockState & aBlockState) const | ||
{ | ||
auto a = mIndex.find(aBlockTypeName); | ||
if (a != mIndex.end()) | ||
{ | ||
auto b = a->second.find(aBlockState); | ||
if (b != a->second.end()) | ||
{ | ||
return b->second; | ||
} | ||
} | ||
return NOT_FOUND; | ||
} | ||
|
||
|
||
|
||
|
||
|
||
void ProtocolBlockTypePalette::clear() | ||
{ | ||
return mIndex.clear(); | ||
} |
Oops, something went wrong.