314 std::unordered_map<std::string, BlockstateProperties> blockstate_properties;
315 std::unordered_map<std::string, std::string> textures;
316 std::unordered_map<std::string, std::string> rendering;
317#if PROTOCOL_VERSION < 347
318 std::unordered_map<std::string, std::unordered_map<int, TintType> > tint_types;
320 std::unordered_map<std::string, TintType> tint_types;
322 const std::string info_file_path = ASSETS_PATH + std::string(
"/custom/Blocks_info.json");
327 std::ifstream file(info_file_path);
331 catch (
const std::runtime_error& e)
333 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
'\n' << e.what());
339 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
" (no colliders found)");
346 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
" (no blocks found)");
350 for (
const auto& info : json[
"blocks"].
get_array())
352 std::string name =
"";
354 if (!info.contains(
"name") || !info[
"name"].is_string())
356 LOG_ERROR(
"Error with an element of blockstates info: \n" << info.Dump());
361 name = info[
"name"].get_string();
362 blockstate_properties[name].name = name;
367 if (info.contains(
"air") && info[
"air"].is_bool())
369 current_block_properties.
air = info[
"air"].get<
bool>();
372 current_block_properties.
solid = info.
contains(
"solid") ? info[
"solid"] :
false;
374 if (info.contains(
"transparent") && info[
"transparent"].is_bool())
376 current_block_properties.
transparent = info[
"transparent"].get<
bool>();
379 if (info.contains(
"lava") && info[
"lava"].is_bool())
381 current_block_properties.
lava = info[
"lava"].get<
bool>();
384 if (info.contains(
"water") && info[
"water"].is_bool())
386 current_block_properties.
water = info[
"water"].get<
bool>();
389 if (info.contains(
"waterlogged") && info[
"waterlogged"].is_bool())
391 current_block_properties.
waterlogged = info[
"waterlogged"].
get<
bool>();
395 current_block_properties.
waterlogged =
"waterlogged=true";
398 if (info.contains(
"climbable") && info[
"climbable"].is_bool())
400 current_block_properties.
climbable = info[
"climbable"].get<
bool>();
403 if (info.contains(
"hazardous") && info[
"hazardous"].is_bool())
405 current_block_properties.
hazardous = info[
"hazardous"].get<
bool>();
408#if PROTOCOL_VERSION < 393
409 current_block_properties.
slime = name ==
"minecraft:slime";
411 current_block_properties.
slime = name ==
"minecraft:slime_block";
414#if PROTOCOL_VERSION < 393
415 current_block_properties.
bed = name ==
"minecraft:bed";
420 current_block_properties.
soul_sand = name ==
"minecraft:soul_sand";
422#if PROTOCOL_VERSION > 498
423 current_block_properties.
honey = name ==
"minecraft:honey_block";
426#if PROTOCOL_VERSION > 404
427 current_block_properties.
scaffolding = name ==
"minecraft:scaffolding";
430#if PROTOCOL_VERSION < 393
431 current_block_properties.
cobweb = name ==
"minecraft:web";
433 current_block_properties.
cobweb = name ==
"minecraft:cobweb";
436#if PROTOCOL_VERSION > 340
441#if PROTOCOL_VERSION > 404
442 current_block_properties.
berry_bush = name ==
"minecraft:sweet_berry_bush";
445#if PROTOCOL_VERSION > 754
446 current_block_properties.
powder_snow = name ==
"minecraft:powder_snow";
449 if (info.contains(
"horizontal_offset") && info[
"horizontal_offset"].is_number())
451 blockstate_properties[name].horizontal_offset = info[
"horizontal_offset"].get_number<
float>();
454 if (info.contains(
"hardness") && info[
"hardness"].is_number())
456 blockstate_properties[name].hardness = info[
"hardness"].get_number<
float>();
459 if (info.contains(
"friction") && info[
"friction"].is_number())
461 blockstate_properties[name].friction = info[
"friction"].get_number<
float>();
464 if (info.contains(
"colliders") && info[
"colliders"].is_number() && info[
"colliders"].get<
int>() < colliders.
size())
466 blockstate_properties[name].colliders = colliders[info[
"colliders"].get<
int>()];
469 if (!info.contains(
"render") || !info[
"render"].is_string())
471 rendering[name] =
"block";
475 rendering[name] = info[
"render"].
get_string();
479 if (info.contains(
"tools") && info[
"tools"].is_array())
481 for (
const auto& tool : info[
"tools"].get_array())
483 if (tool.is_string())
485 const std::string tool_name = tool.get_string();
486 if (tool_name ==
"any")
488 blockstate_properties[name].any_tool_harvest =
true;
494 blockstate_properties[name].best_tools.push_back(
502 else if (tool.is_object())
504 if (tool.contains(
"tool") && tool[
"tool"].is_string())
509 if (tool.contains(
"min_material") && tool[
"min_material"].is_string())
519 if (tool.contains(
"multiplier") && tool[
"multiplier"].is_number())
521 best_tool.
multiplier = tool[
"multiplier"].get<
float>();
528 blockstate_properties[name].best_tools.push_back(best_tool);
535 if (info.contains(
"texture") && info[
"texture"].is_string())
537 textures[name] = info[
"texture"].get_string();
541 if (info.contains(
"tintType") && info[
"tintType"].is_string())
543 std::string tint_type_string;
545 tint_type_string = info[
"tintType"].get_string();
546 if (tint_type_string ==
"grass")
550 else if (tint_type_string ==
"leaves")
554 else if (tint_type_string ==
"water")
558 else if (tint_type_string ==
"redstone")
563#if PROTOCOL_VERSION < 347
564 tint_types[name] = std::unordered_map<int, TintType>({ { -1, tint_type } });
566 tint_types[name] = tint_type;
569#if PROTOCOL_VERSION < 347
571 else if (info.contains(
"tintTypes") && info[
"tintType"].is_object())
573 tint_types[name] = std::unordered_map<int, TintType>({});
574 for (
const auto& [key, val]: info[
"tintType"].get_object())
577 std::string tint_type_string = val.get_string();
579 if (tint_type_string ==
"grass")
583 else if (tint_type_string ==
"leaves")
587 else if (tint_type_string ==
"water")
591 else if (tint_type_string ==
"redstone")
596 tint_types[name][std::stoi(key)] = tint_type;
602#if PROTOCOL_VERSION < 347
603 tint_types[name] = std::unordered_map<int, TintType>({ { -1,
TintType::None } });
611#if PROTOCOL_VERSION < 347
650 const std::string file_path = ASSETS_PATH + std::string(
"/custom/Blocks.json");
654 std::ifstream file(file_path);
658 catch (
const std::runtime_error& e)
660 LOG_ERROR(
"Error reading block file at " << file_path <<
'\n' << e.what());
664#if PROTOCOL_VERSION < 347
668 LOG_ERROR(
"Error block file at " << file_path <<
" is not a json array as expected");
673 for (
const auto& element : json.
get_array())
675 const std::string& blockstate_name = element[
"name"].get_string();
677 if (rendering.find(blockstate_name) == rendering.end() ||
678 blockstate_properties.find(blockstate_name) == blockstate_properties.end() ||
679 tint_types.find(blockstate_name) == tint_types.end())
681 LOG_ERROR(
"Error trying to get information for blockstate " << blockstate_name);
688 props.
variables = std::vector<std::string>();
690 if (element.contains(
"id") && element[
"id"].is_number())
692 props.
id = element[
"id"].get_number<
int>();
695 const std::string& render = rendering[blockstate_name];
697 const bool fluid_falling = props.metadata & 0b1000;
698 const int fluid_level = 1 + (props.metadata & 0b111);
700 if (render ==
"none")
705 blockstates[props.
id][0] = std::make_unique<Blockstate>(props);
707 else if (render ==
"block" || render ==
"fluid" || render ==
"other")
709 if (render ==
"fluid" && textures.find(blockstate_name) == textures.end())
711 LOG_ERROR(
"Error, blockstate " << blockstate_name <<
" is a fluid, but it does not have a texture file specified in Blocks_info.json");
714 if (!element.contains(
"metadata"))
716 LOG_ERROR(
"Error, no metadata found for block " << blockstate_name);
719 for (
const auto& metadata_obj : element[
"metadata"].get_array())
721 props.metadata = metadata_obj[
"value"].get_number<
int>();
722 props.
path = metadata_obj[
"blockstate"].get_string();
723 props.
variables = std::vector<std::string>();
724 if (metadata_obj.contains(
"variables"))
726 for (
const auto& s : metadata_obj[
"variables"].get_array())
728 props.
variables.push_back(s.get_string());
733 if (tint_types.find(blockstate_name) != tint_types.end())
735 if (tint_types[blockstate_name].find(-1) != tint_types[blockstate_name].end())
737 props.
tint_type = tint_types[blockstate_name][-1];
739 else if (tint_types[blockstate_name].find(props.metadata) != tint_types[blockstate_name].end())
741 props.
tint_type = tint_types[blockstate_name][props.metadata];
748 if (render ==
"fluid")
751 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]));
755 props.
custom = render ==
"other";
756 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props);
762 if (render ==
"fluid")
765 blockstates[props.
id][0] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
766 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]));
770 props.
custom = render ==
"other";
772 blockstates[props.
id][0] = std::make_unique<Blockstate>(props);
773 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props);
782 LOG_ERROR(
"Error block file at " << file_path <<
" is not a json object as expected");
786 for (
const auto& [blockstate_name, element]: json.
get_object())
788 if (!element.contains(
"states") || !element[
"states"].is_array())
793 for (
const auto& blockstate : element[
"states"].get_array())
795 if (rendering.find(blockstate_name) == rendering.end() ||
796 blockstate_properties.find(blockstate_name) == blockstate_properties.end() ||
797 tint_types.find(blockstate_name) == tint_types.end())
799 LOG_ERROR(
"Error trying to get information for blockstate " << blockstate_name);
805 props.
variables = std::vector<std::string>();
807 if (blockstate.contains(
"id") && blockstate[
"id"].is_number())
809 props.
id = blockstate[
"id"].get_number<
int>();
813 LOG_ERROR(
"Error trying to read the id of block " << blockstate_name);
817 const std::string& render = rendering[blockstate_name];
821 bool fluid_falling =
false;
822 if (blockstate.contains(
"properties") && blockstate[
"properties"].is_object())
824 for (
const auto& [key, val]: blockstate[
"properties"].get_object())
826 props.
variables.push_back(key +
"=" + val.get_string());
827 if (render ==
"fluid" && key ==
"level")
829 fluid_level = std::stoi(val.get_string());
830 fluid_falling = fluid_level & 0b1000;
831 fluid_level = 1 + (fluid_level & 0b111);
836 if (render ==
"none")
843 else if (render ==
"fluid")
845 if (textures.find(blockstate_name) == textures.end())
847 LOG_ERROR(
"Error, blockstate " << blockstate_name <<
" is a fluid, but it does not have a texture file specified in Blocks_info.json");
851 props.
tint_type = tint_types[blockstate_name];
852 blockstates[props.
id] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
855 else if (render ==
"block" || render ==
"other")
857 props.
custom = render ==
"other";
858 props.
tint_type = tint_types[blockstate_name];
859 props.
path = blockstate_name.substr(10);
864 LOG_WARNING(
"No known rendering method defined for block: " << blockstate_name);