308 std::unordered_map<std::string, BlockstateProperties> blockstate_properties;
309 std::unordered_map<std::string, std::string> textures;
310 std::unordered_map<std::string, std::string> rendering;
311#if PROTOCOL_VERSION < 347
312 std::unordered_map<std::string, std::unordered_map<int, TintType> > tint_types;
314 std::unordered_map<std::string, TintType> tint_types;
316 const std::string info_file_path = ASSETS_PATH + std::string(
"/custom/Blocks_info.json");
321 std::ifstream file(info_file_path);
325 catch (
const std::runtime_error& e)
327 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
'\n' << e.what());
333 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
" (no colliders found)");
340 LOG_ERROR(
"Error reading info block file at " << info_file_path <<
" (no blocks found)");
344 for (
const auto& info : json[
"blocks"].
get_array())
346 std::string name =
"";
348 if (!info.contains(
"name") || !info[
"name"].is_string())
350 LOG_ERROR(
"Error with an element of blockstates info: \n" << info.Dump());
355 name = info[
"name"].get_string();
356 blockstate_properties[name].name = name;
361 if (info.contains(
"air") && info[
"air"].is_bool())
363 current_block_properties.
air = info[
"air"].get<
bool>();
366 current_block_properties.
solid = info.
contains(
"solid") ? info[
"solid"] :
false;
368 if (info.contains(
"transparent") && info[
"transparent"].is_bool())
370 current_block_properties.
transparent = info[
"transparent"].get<
bool>();
373 if (info.contains(
"lava") && info[
"lava"].is_bool())
375 current_block_properties.
lava = info[
"lava"].get<
bool>();
378 if (info.contains(
"water") && info[
"water"].is_bool())
380 current_block_properties.
water = info[
"water"].get<
bool>();
383 if (info.contains(
"waterlogged") && info[
"waterlogged"].is_bool())
385 current_block_properties.
waterlogged = info[
"waterlogged"].
get<
bool>();
389 current_block_properties.
waterlogged =
"waterlogged=true";
392 if (info.contains(
"climbable") && info[
"climbable"].is_bool())
394 current_block_properties.
climbable = info[
"climbable"].get<
bool>();
397 if (info.contains(
"hazardous") && info[
"hazardous"].is_bool())
399 current_block_properties.
hazardous = info[
"hazardous"].get<
bool>();
402#if PROTOCOL_VERSION < 393
403 current_block_properties.
slime = name ==
"minecraft:slime";
405 current_block_properties.
slime = name ==
"minecraft:slime_block";
408#if PROTOCOL_VERSION < 393
409 current_block_properties.
bed = name ==
"minecraft:bed";
414 current_block_properties.
soul_sand = name ==
"minecraft:soul_sand";
416#if PROTOCOL_VERSION > 498
417 current_block_properties.
honey = name ==
"minecraft:honey_block";
420#if PROTOCOL_VERSION > 404
421 current_block_properties.
scaffolding = name ==
"minecraft:scaffolding";
424#if PROTOCOL_VERSION < 393
425 current_block_properties.
cobweb = name ==
"minecraft:web";
427 current_block_properties.
cobweb = name ==
"minecraft:cobweb";
430#if PROTOCOL_VERSION > 340
435#if PROTOCOL_VERSION > 404
436 current_block_properties.
berry_bush = name ==
"minecraft:sweet_berry_bush";
439#if PROTOCOL_VERSION > 754
440 current_block_properties.
powder_snow = name ==
"minecraft:powder_snow";
443 if (info.contains(
"horizontal_offset") && info[
"horizontal_offset"].is_number())
445 blockstate_properties[name].horizontal_offset = info[
"horizontal_offset"].get_number<
float>();
448 if (info.contains(
"hardness") && info[
"hardness"].is_number())
450 blockstate_properties[name].hardness = info[
"hardness"].get_number<
float>();
453 if (info.contains(
"friction") && info[
"friction"].is_number())
455 blockstate_properties[name].friction = info[
"friction"].get_number<
float>();
458 if (info.contains(
"colliders") && info[
"colliders"].is_number() && info[
"colliders"].get<
int>() < colliders.
size())
460 blockstate_properties[name].colliders = colliders[info[
"colliders"].get<
int>()];
463 if (!info.contains(
"render") || !info[
"render"].is_string())
465 rendering[name] =
"block";
469 rendering[name] = info[
"render"].
get_string();
473 if (info.contains(
"tools") && info[
"tools"].is_array())
475 for (
const auto& tool : info[
"tools"].get_array())
477 if (tool.is_string())
479 const std::string tool_name = tool.get_string();
480 if (tool_name ==
"any")
482 blockstate_properties[name].any_tool_harvest =
true;
488 blockstate_properties[name].best_tools.push_back(
496 else if (tool.is_object())
498 if (tool.contains(
"tool") && tool[
"tool"].is_string())
503 if (tool.contains(
"min_material") && tool[
"min_material"].is_string())
513 if (tool.contains(
"multiplier") && tool[
"multiplier"].is_number())
515 best_tool.
multiplier = tool[
"multiplier"].get<
float>();
522 blockstate_properties[name].best_tools.push_back(best_tool);
529 if (info.contains(
"texture") && info[
"texture"].is_string())
531 textures[name] = info[
"texture"].get_string();
535 if (info.contains(
"tintType") && info[
"tintType"].is_string())
537 std::string tint_type_string;
539 tint_type_string = info[
"tintType"].get_string();
540 if (tint_type_string ==
"grass")
544 else if (tint_type_string ==
"leaves")
548 else if (tint_type_string ==
"water")
552 else if (tint_type_string ==
"redstone")
557#if PROTOCOL_VERSION < 347
558 tint_types[name] = std::unordered_map<int, TintType>({ { -1, tint_type } });
560 tint_types[name] = tint_type;
563#if PROTOCOL_VERSION < 347
565 else if (info.contains(
"tintTypes") && info[
"tintType"].is_object())
567 tint_types[name] = std::unordered_map<int, TintType>({});
568 for (
const auto& [key, val]: info[
"tintType"].get_object())
571 std::string tint_type_string = val.get_string();
573 if (tint_type_string ==
"grass")
577 else if (tint_type_string ==
"leaves")
581 else if (tint_type_string ==
"water")
585 else if (tint_type_string ==
"redstone")
590 tint_types[name][std::stoi(key)] = tint_type;
596#if PROTOCOL_VERSION < 347
597 tint_types[name] = std::unordered_map<int, TintType>({ { -1,
TintType::None } });
605#if PROTOCOL_VERSION < 347
644 const std::string file_path = ASSETS_PATH + std::string(
"/custom/Blocks.json");
648 std::ifstream file(file_path);
652 catch (
const std::runtime_error& e)
654 LOG_ERROR(
"Error reading block file at " << file_path <<
'\n' << e.what());
658#if PROTOCOL_VERSION < 347
662 LOG_ERROR(
"Error block file at " << file_path <<
" is not a json array as expected");
667 for (
const auto& element : json.
get_array())
669 const std::string& blockstate_name = element[
"name"].get_string();
671 if (rendering.find(blockstate_name) == rendering.end() ||
672 blockstate_properties.find(blockstate_name) == blockstate_properties.end() ||
673 tint_types.find(blockstate_name) == tint_types.end())
675 LOG_ERROR(
"Error trying to get information for blockstate " << blockstate_name);
682 props.
variables = std::vector<std::string>();
684 if (element.contains(
"id") && element[
"id"].is_number())
686 props.
id = element[
"id"].get_number<
int>();
689 const std::string& render = rendering[blockstate_name];
691 const bool fluid_falling = props.metadata & 0b1000;
692 const int fluid_level = 1 + (props.metadata & 0b111);
694 if (render ==
"none")
699 blockstates[props.
id][0] = std::make_unique<Blockstate>(props);
701 else if (render ==
"block" || render ==
"fluid" || render ==
"other")
703 if (render ==
"fluid" && textures.find(blockstate_name) == textures.end())
705 LOG_ERROR(
"Error, blockstate " << blockstate_name <<
" is a fluid, but it does not have a texture file specified in Blocks_info.json");
708 if (!element.contains(
"metadata"))
710 LOG_ERROR(
"Error, no metadata found for block " << blockstate_name);
713 for (
const auto& metadata_obj : element[
"metadata"].get_array())
715 props.metadata = metadata_obj[
"value"].get_number<
int>();
716 props.
path = metadata_obj[
"blockstate"].get_string();
717 props.
variables = std::vector<std::string>();
718 if (metadata_obj.contains(
"variables"))
720 for (
const auto& s : metadata_obj[
"variables"].get_array())
722 props.
variables.push_back(s.get_string());
727 if (tint_types.find(blockstate_name) != tint_types.end())
729 if (tint_types[blockstate_name].find(-1) != tint_types[blockstate_name].end())
731 props.
tint_type = tint_types[blockstate_name][-1];
733 else if (tint_types[blockstate_name].find(props.metadata) != tint_types[blockstate_name].end())
735 props.
tint_type = tint_types[blockstate_name][props.metadata];
742 if (render ==
"fluid")
745 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]));
749 props.
custom = render ==
"other";
750 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props);
756 if (render ==
"fluid")
759 blockstates[props.
id][0] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
760 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]));
764 props.
custom = render ==
"other";
766 blockstates[props.
id][0] = std::make_unique<Blockstate>(props);
767 blockstates[props.
id][props.metadata] = std::make_unique<Blockstate>(props);
776 LOG_ERROR(
"Error block file at " << file_path <<
" is not a json object as expected");
780 for (
const auto& [blockstate_name, element]: json.
get_object())
782 if (!element.contains(
"states") || !element[
"states"].is_array())
787 for (
const auto& blockstate : element[
"states"].get_array())
789 if (rendering.find(blockstate_name) == rendering.end() ||
790 blockstate_properties.find(blockstate_name) == blockstate_properties.end() ||
791 tint_types.find(blockstate_name) == tint_types.end())
793 LOG_ERROR(
"Error trying to get information for blockstate " << blockstate_name);
799 props.
variables = std::vector<std::string>();
801 if (blockstate.contains(
"id") && blockstate[
"id"].is_number())
803 props.
id = blockstate[
"id"].get_number<
int>();
807 LOG_ERROR(
"Error trying to read the id of block " << blockstate_name);
811 const std::string& render = rendering[blockstate_name];
815 bool fluid_falling =
false;
816 if (blockstate.contains(
"properties") && blockstate[
"properties"].is_object())
818 for (
const auto& [key, val]: blockstate[
"properties"].get_object())
820 props.
variables.push_back(key +
"=" + val.get_string());
821 if (render ==
"fluid" && key ==
"level")
823 fluid_level = std::stoi(val.get_string());
824 fluid_falling = fluid_level & 0b1000;
825 fluid_level = 1 + (fluid_level & 0b111);
830 if (render ==
"none")
837 else if (render ==
"fluid")
839 if (textures.find(blockstate_name) == textures.end())
841 LOG_ERROR(
"Error, blockstate " << blockstate_name <<
" is a fluid, but it does not have a texture file specified in Blocks_info.json");
845 props.
tint_type = tint_types[blockstate_name];
846 blockstates[props.
id] = std::make_unique<Blockstate>(props,
Model::GetModel(fluid_falling ? 1.0 : (1.0 - fluid_level / 9.0), textures[blockstate_name]));
849 else if (render ==
"block" || render ==
"other")
851 props.
custom = render ==
"other";
852 props.
tint_type = tint_types[blockstate_name];
853 props.
path = blockstate_name.substr(10);
858 LOG_WARNING(
"No known rendering method defined for block: " << blockstate_name);