282 std::unordered_map<std::string, BlockstateProperties> blockstate_properties;
283 std::unordered_map<std::string, std::string> textures;
284 std::unordered_map<std::string, std::string> rendering;
285#if PROTOCOL_VERSION < 347
286 std::unordered_map<std::string, std::unordered_map<int, TintType> > tint_types;
288 std::unordered_map<std::string, TintType> tint_types;
290 const std::string info_file_path = ASSETS_PATH + std::string(
"/custom/Blocks_info.json");
295 std::ifstream file(info_file_path);
299 catch (
const std::runtime_error& e)
301 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
'\n' << e.what());
307 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
" (no colliders found)");
314 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
" (no blocks found)");
318 for (
const auto& info : json[
"blocks"].
get_array())
320 std::string name =
"";
322 if (!info.contains(
"name") || !info[
"name"].is_string())
324 LOG_ERROR(
"Error with an element of blockstates info: \n" << info.Dump());
329 name = info[
"name"].get_string();
330 blockstate_properties[name].name = name;
335 if (info.contains(
"air") && info[
"air"].is_bool())
337 current_block_properties.
air = info[
"air"].get<
bool>();
340 current_block_properties.
solid = info.
contains(
"solid") ? info[
"solid"] :
false;
342 if (info.contains(
"transparent") && info[
"transparent"].is_bool())
344 current_block_properties.
transparent = info[
"transparent"].get<
bool>();
347 if (info.contains(
"lava") && info[
"lava"].is_bool())
349 current_block_properties.
lava = info[
"lava"].get<
bool>();
352 if (info.contains(
"water") && info[
"water"].is_bool())
354 current_block_properties.
water = info[
"water"].get<
bool>();
357 if (info.contains(
"waterlogged") && info[
"waterlogged"].is_bool())
359 current_block_properties.
waterlogged = info[
"waterlogged"].
get<
bool>();
363 current_block_properties.
waterlogged =
"waterlogged=true";
366 if (info.contains(
"climbable") && info[
"climbable"].is_bool())
368 current_block_properties.
climbable = info[
"climbable"].get<
bool>();
371 if (info.contains(
"hazardous") && info[
"hazardous"].is_bool())
373 current_block_properties.
hazardous = info[
"hazardous"].get<
bool>();
376#if PROTOCOL_VERSION < 393
377 current_block_properties.
slime = name ==
"minecraft:slime";
379 current_block_properties.
slime = name ==
"minecraft:slime_block";
382#if PROTOCOL_VERSION < 393
383 current_block_properties.
bed = name ==
"minecraft:bed";
388 current_block_properties.
soul_sand = name ==
"minecraft:soul_sand";
390#if PROTOCOL_VERSION > 498
391 current_block_properties.
honey = name ==
"minecraft:honey_block";
394#if PROTOCOL_VERSION > 404
395 current_block_properties.
scaffolding = name ==
"minecraft:scaffolding";
398#if PROTOCOL_VERSION < 393
399 current_block_properties.
cobweb = name ==
"minecraft:web";
401 current_block_properties.
cobweb = name ==
"minecraft:cobweb";
404#if PROTOCOL_VERSION > 340
409#if PROTOCOL_VERSION > 404
410 current_block_properties.
berry_bush = name ==
"minecraft:sweet_berry_bush";
413#if PROTOCOL_VERSION > 754
414 current_block_properties.
powder_snow = name ==
"minecraft:powder_snow";
417 if (info.contains(
"horizontal_offset") && info[
"horizontal_offset"].is_number())
419 blockstate_properties[name].horizontal_offset = info[
"horizontal_offset"].get_number<
float>();
422 if (info.contains(
"hardness") && info[
"hardness"].is_number())
424 blockstate_properties[name].hardness = info[
"hardness"].get_number<
float>();
427 if (info.contains(
"friction") && info[
"friction"].is_number())
429 blockstate_properties[name].friction = info[
"friction"].get_number<
float>();
432 if (info.contains(
"colliders") && info[
"colliders"].is_number() && info[
"colliders"].get<
int>() < colliders.
size())
434 blockstate_properties[name].colliders = colliders[info[
"colliders"].get<
int>()];
437 if (!info.contains(
"render") || !info[
"render"].is_string())
439 rendering[name] =
"block";
443 rendering[name] = info[
"render"].
get_string();
447 if (info.contains(
"tools") && info[
"tools"].is_array())
449 for (
const auto& tool : info[
"tools"].get_array())
451 if (tool.is_string())
453 const std::string tool_name = tool.get_string();
454 if (tool_name ==
"any")
456 blockstate_properties[name].any_tool_harvest =
true;
462 blockstate_properties[name].best_tools.push_back(
470 else if (tool.is_object())
472 if (tool.contains(
"tool") && tool[
"tool"].is_string())
477 if (tool.contains(
"min_material") && tool[
"min_material"].is_string())
487 if (tool.contains(
"multiplier") && tool[
"multiplier"].is_number())
489 best_tool.
multiplier = tool[
"multiplier"].get<
float>();
496 blockstate_properties[name].best_tools.push_back(best_tool);
503 if (info.contains(
"texture") && info[
"texture"].is_string())
505 textures[name] = info[
"texture"].get_string();
509 if (info.contains(
"tintType") && info[
"tintType"].is_string())
511 std::string tint_type_string;
513 tint_type_string = info[
"tintType"].get_string();
514 if (tint_type_string ==
"grass")
518 else if (tint_type_string ==
"leaves")
522 else if (tint_type_string ==
"water")
526 else if (tint_type_string ==
"redstone")
531#if PROTOCOL_VERSION < 347
532 tint_types[name] = std::unordered_map<int, TintType>({ { -1, tint_type } });
534 tint_types[name] = tint_type;
537#if PROTOCOL_VERSION < 347
539 else if (info.contains(
"tintTypes") && info[
"tintType"].is_object())
541 tint_types[name] = std::unordered_map<int, TintType>({});
542 for (
const auto& [key, val]: info[
"tintType"].get_object())
545 std::string tint_type_string = val.get_string();
547 if (tint_type_string ==
"grass")
551 else if (tint_type_string ==
"leaves")
555 else if (tint_type_string ==
"water")
559 else if (tint_type_string ==
"redstone")
564 tint_types[name][std::stoi(key)] = tint_type;
570#if PROTOCOL_VERSION < 347
571 tint_types[name] = std::unordered_map<int, TintType>({ { -1,
TintType::None } });
579#if PROTOCOL_VERSION < 347
618 const std::string file_path = ASSETS_PATH + std::string(
"/custom/Blocks.json");
622 std::ifstream file(file_path);
626 catch (
const std::runtime_error& e)
628 LOG_ERROR(
"Error reading block file at " << file_path <<
'\n' << e.what());
632#if PROTOCOL_VERSION < 347
636 LOG_ERROR(
"Error block file at " << file_path <<
" is not a json array as expected");
641 for (
const auto& element : json.
get_array())
643 const std::string& blockstate_name = element[
"name"].get_string();
645 if (rendering.find(blockstate_name) == rendering.end() ||
646 blockstate_properties.find(blockstate_name) == blockstate_properties.end() ||
647 tint_types.find(blockstate_name) == tint_types.end())
649 LOG_ERROR(
"Error trying to get information for blockstate " << blockstate_name);
656 props.
variables = std::vector<std::string>();
658 if (element.contains(
"id") && element[
"id"].is_number())
660 props.
id = element[
"id"].get_number<
int>();
663 const std::string& render = rendering[blockstate_name];
665 const bool fluid_falling = props.metadata & 0b1000;
666 const int fluid_level = 1 + (props.metadata & 0b111);
668 if (render ==
"none")
673 blockstates[props.
id][0] = std::make_unique<Blockstate>(props);
675 else if (render ==
"block" || render ==
"fluid" || render ==
"other")
677 if (render ==
"fluid" && textures.find(blockstate_name) == textures.end())
679 LOG_ERROR(
"Error, blockstate " << blockstate_name <<
" is a fluid, but it does not have a texture file specified in Blocks_info.json");
682 if (!element.contains(
"metadata"))
684 LOG_ERROR(
"Error, no metadata found for block " << blockstate_name);
687 for (
const auto& metadata_obj : element[
"metadata"].get_array())
689 props.metadata = metadata_obj[
"value"].get_number<
int>();
690 props.
path = metadata_obj[
"blockstate"].get_string();
691 props.
variables = std::vector<std::string>();
692 if (metadata_obj.contains(
"variables"))
694 for (
const auto& s : metadata_obj[
"variables"].get_array())
696 props.
variables.push_back(s.get_string());
701 if (tint_types.find(blockstate_name) != tint_types.end())
703 if (tint_types[blockstate_name].find(-1) != tint_types[blockstate_name].end())
705 props.
tint_type = tint_types[blockstate_name][-1];
707 else if (tint_types[blockstate_name].find(props.metadata) != tint_types[blockstate_name].end())
709 props.
tint_type = tint_types[blockstate_name][props.metadata];
716 if (render ==
"fluid")
719 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
723 props.
custom = render ==
"other";
724 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props);
730 if (render ==
"fluid")
733 blockstates[props.
id][0] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
734 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
738 props.
custom = render ==
"other";
740 blockstates[props.
id][0] = std::make_unique<Blockstate>(props);
741 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props);
750 LOG_ERROR(
"Error block file at " << file_path <<
" is not a json object as expected");
754 for (
const auto& [blockstate_name, element]: json.
get_object())
756 if (!element.contains(
"states") || !element[
"states"].is_array())
761 for (
const auto& blockstate : element[
"states"].get_array())
763 if (rendering.find(blockstate_name) == rendering.end() ||
764 blockstate_properties.find(blockstate_name) == blockstate_properties.end() ||
765 tint_types.find(blockstate_name) == tint_types.end())
767 LOG_ERROR(
"Error trying to get information for blockstate " << blockstate_name);
773 props.
variables = std::vector<std::string>();
775 if (blockstate.contains(
"id") && blockstate[
"id"].is_number())
777 props.
id = blockstate[
"id"].get_number<
int>();
781 LOG_ERROR(
"Error trying to read the id of block " << blockstate_name);
785 const std::string& render = rendering[blockstate_name];
789 bool fluid_falling =
false;
790 if (blockstate.contains(
"properties") && blockstate[
"properties"].is_object())
792 for (
const auto& [key, val]: blockstate[
"properties"].get_object())
794 props.
variables.push_back(key +
"=" + val.get_string());
795 if (render ==
"fluid" && key ==
"level")
797 fluid_level = std::stoi(val.get_string());
798 fluid_falling = fluid_level & 0b1000;
799 fluid_level = 1 + (fluid_level & 0b111);
804 if (render ==
"none")
811 else if (render ==
"fluid")
813 if (textures.find(blockstate_name) == textures.end())
815 LOG_ERROR(
"Error, blockstate " << blockstate_name <<
" is a fluid, but it does not have a texture file specified in Blocks_info.json");
819 props.
tint_type = tint_types[blockstate_name];
820 blockstates[props.
id] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
823 else if (render ==
"block" || render ==
"other")
825 props.
custom = render ==
"other";
826 props.
tint_type = tint_types[blockstate_name];
827 props.
path = blockstate_name.substr(10);
832 LOG_WARNING(
"No known rendering method defined for block: " << blockstate_name);