11#if PROTOCOL_VERSION < 719
17#if PROTOCOL_VERSION > 758
29 std::shared_lock<std::shared_mutex> lock(
world_mutex);
31 const int chunk_x =
static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH)));
32 const int chunk_z =
static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)));
44#if PROTOCOL_VERSION < 757
47 std::shared_lock<std::shared_mutex> lock(
world_mutex);
54#if PROTOCOL_VERSION < 757
57 std::shared_lock<std::shared_mutex> lock(
world_mutex);
64 std::shared_lock<std::shared_mutex> lock(
world_mutex);
65#if PROTOCOL_VERSION < 719
75 std::shared_lock<std::shared_mutex> lock(
world_mutex);
76 auto it =
terrain.find({ x,z });
81 return it->second.GetModifiedSinceLastRender();
90 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
91 auto it =
terrain.find({ x,z });
94 return std::optional<Chunk>();
96 it->second.SetModifiedSinceLastRender(
false);
97 return std::optional<Chunk>(it->second);
99 return std::optional<Chunk>();
103#if PROTOCOL_VERSION < 719
104 void World::LoadChunk(
const int x,
const int z,
const Dimension dim,
const std::thread::id& loader_id)
106 void World::LoadChunk(
const int x,
const int z,
const std::string& dim,
const std::thread::id& loader_id)
109 std::scoped_lock<std::shared_mutex> lock(world_mutex);
110 LoadChunkImpl(x, z, dim, loader_id);
115 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
121 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
124 const int load_count = it->second.RemoveLoader(loader_id);
138 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
144 std::shared_lock<std::shared_mutex> lock(
world_mutex);
150 std::shared_lock<std::shared_mutex> lock(
world_mutex);
151 std::vector<const Blockstate*> output(pos.size());
152 for (
size_t i = 0; i < pos.size(); ++i)
165 std::vector<AABB> output;
168 std::shared_lock<std::shared_mutex> lock(
world_mutex);
169 for (
int y =
static_cast<int>(std::floor(min_aabb.
y)) - 1; y <= static_cast<int>(std::floor(max_aabb.
y)); ++y)
172 for (
int z =
static_cast<int>(std::floor(min_aabb.
z)); z <= static_cast<int>(std::floor(max_aabb.
z)); ++z)
175 for (
int x =
static_cast<int>(std::floor(min_aabb.
x)); x <= static_cast<int>(std::floor(max_aabb.
x)); ++x)
179 if (block ==
nullptr || !block->
IsSolid())
185 output.insert(output.end(), colliders.begin(), colliders.end());
194 std::shared_lock<std::shared_mutex> lock(
world_mutex);
196 std::vector<Position> horizontal_neighbours = {
207 for (
const Position& neighbour_pos : horizontal_neighbours)
215 if (neighbour_fluid_height == 0.0f)
220 if (block_below_neighbour !=
nullptr &&
223 const float block_below_neighbour_fluid_height = block_below_neighbour->
GetFluidHeight();
224 if (block_below_neighbour_fluid_height > 0.0f)
226 flow.
x += (current_fluid_height - block_below_neighbour_fluid_height + 0.8888889f) * neighbour_pos.x;
227 flow.
z += (current_fluid_height - block_below_neighbour_fluid_height + 0.8888889f) * neighbour_pos.z;
234 flow.
x += (current_fluid_height - neighbour_fluid_height) * neighbour_pos.x;
235 flow.
z += (current_fluid_height - neighbour_fluid_height) * neighbour_pos.z;
241 for (
const Position& neighbour_pos : horizontal_neighbours)
244 if (neighbour ==
nullptr)
249 if (above_neighbour ==
nullptr)
271#if PROTOCOL_VERSION < 358
272 void World::SetBiome(
const int x,
const int z,
const unsigned char biome)
273#elif PROTOCOL_VERSION < 552
279 std::scoped_lock<std::shared_mutex> lock(world_mutex);
280#if PROTOCOL_VERSION < 552
281 SetBiomeImpl(x, z, biome);
283 SetBiomeImpl(x, y, z, biome);
289 std::shared_lock<std::shared_mutex> lock(
world_mutex);
291 static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH))),
292 static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)))
302#if PROTOCOL_VERSION < 552
303 return it->second.GetBiome(in_chunk_x, in_chunk_z);
305 return it->second.GetBiome(in_chunk_x, pos.
y, in_chunk_z);
311 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
313 static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH))),
314 static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)))
317 if (it !=
terrain.end() && it->second.GetHasSkyLight())
321 it->second.SetSkyLight(
Position(in_chunk_x, pos.
y, in_chunk_z), skylight);
327 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
329 static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH))),
330 static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)))
337 it->second.SetBlockLight(
Position(in_chunk_x, pos.
y, in_chunk_z), blocklight);
343 std::shared_lock<std::shared_mutex> lock(
world_mutex);
345 static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH))),
346 static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)))
355 return it->second.GetSkyLight(
Position(in_chunk_x, pos.
y, in_chunk_z));
360 std::shared_lock<std::shared_mutex> lock(
world_mutex);
362 static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH))),
363 static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)))
372 return it->second.GetBlockLight(
Position(in_chunk_x, pos.
y, in_chunk_z));
377 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
379 static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH))),
380 static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)))
395 it->second.SetBlockEntityData(chunk_pos, data);
399 it->second.RemoveBlockEntityData(chunk_pos);
405 std::shared_lock<std::shared_mutex> lock(
world_mutex);
407 static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH))),
408 static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)))
422 return it->second.GetBlockEntityData(chunk_pos);
425#if PROTOCOL_VERSION < 719
431 std::shared_lock<std::shared_mutex> lock(world_mutex);
432 auto it = terrain.find({ x, z });
433 if (it == terrain.end())
435#if PROTOCOL_VERSION < 719
436 return Dimension::None;
442 return index_dimension_map.at(it->second.GetDimensionIndex());
445#if PROTOCOL_VERSION < 719
451 std::shared_lock<std::shared_mutex> lock(world_mutex);
452 return current_dimension;
455#if PROTOCOL_VERSION < 719
461 std::scoped_lock<std::shared_mutex> lock(world_mutex);
462 SetCurrentDimensionImpl(dimension);
465#if PROTOCOL_VERSION > 756
468 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
474 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
479#if PROTOCOL_VERSION > 718
482 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
494 static_cast<int>(std::floor(origin.
x)),
495 static_cast<int>(std::floor(origin.
y)),
496 static_cast<int>(std::floor(origin.
z))
500 Vector3<double> step((0.0 < direction.
x) - (direction.
x < 0.0), (0.0 < direction.
y) - (direction.
y < 0.0), (0.0 < direction.
z) - (direction.
z < 0.0));
508 for (
int i = 0; i < 3; ++i)
510 bool isInteger = std::round(origin[i]) == origin[i];
511 if (direction[i] < 0 && isInteger)
517 if (direction[i] > 0)
519 tMax[i] = ((origin[i] == 0.0f) ? 1.0f : std::ceil(origin[i]) - origin[i]) / std::abs(direction[i]);
521 else if (direction[i] < 0)
523 tMax[i] = (origin[i] - std::floor(origin[i])) / std::abs(direction[i]);
527 tMax[i] = std::numeric_limits<double>::max();
531 if (direction[i] == 0)
533 tDelta[i] = std::numeric_limits<double>::max();
537 tDelta[i] = step[i] / direction[i];
541 if (direction.
x == 0 && direction.
y == 0 && direction.
z == 0)
543 throw std::runtime_error(
"Raycasting with null direction");
546 const float radius = max_radius /
static_cast<float>(std::sqrt(direction.
x * direction.
x + direction.
y * direction.
y + direction.
z * direction.
z));
552 if (block !=
nullptr && !block->
IsAir())
556 if (collider.Intersect(origin, direction))
565 if (tMax.
x < tMax.
y && tMax.
x < tMax.
z)
572 out_pos.
x +=
static_cast<int>(std::round(step.
x));
574 out_normal.
x = -
static_cast<int>(std::round(step.
x));
578 else if (tMax.
y < tMax.
x && tMax.
y < tMax.
z)
584 out_pos.
y +=
static_cast<int>(std::round(step.
y));
587 out_normal[1] = -
static_cast<int>(std::round(step.
y));
597 out_pos.
z +=
static_cast<int>(std::round(step.
z));
601 out_normal.
x = -
static_cast<int>(std::round(step.
z));
606#if PROTOCOL_VERSION > 758
615 std::shared_lock<std::shared_mutex> lock(
world_mutex);
621 for (
int y =
static_cast<int>(std::floor(min_aabb.
y)) - 1; y <= static_cast<int>(std::floor(max_aabb.
y)); ++y)
624 for (
int z =
static_cast<int>(std::floor(min_aabb.
z)); z <= static_cast<int>(std::floor(max_aabb.
z)); ++z)
627 for (
int x =
static_cast<int>(std::floor(min_aabb.
x)); x <= static_cast<int>(std::floor(max_aabb.
x)); ++x)
632 if (block ==
nullptr)
665 std::shared_lock<std::shared_mutex> lock(
world_mutex);
671 std::optional<Position> output = std::optional<Position>();
672 double min_distance = std::numeric_limits<double>::max();
673 for (
int y =
static_cast<int>(std::floor(min_aabb.
y)) - 1; y <= static_cast<int>(std::floor(max_aabb.
y)); ++y)
676 for (
int z =
static_cast<int>(std::floor(min_aabb.
z)); z <= static_cast<int>(std::floor(max_aabb.
z)); ++z)
679 for (
int x =
static_cast<int>(std::floor(min_aabb.
x)); x <= static_cast<int>(std::floor(max_aabb.
x)); ++x)
684 if (block ==
nullptr || !block->
IsSolid())
694 if (distance < min_distance)
696 min_distance = distance;
710 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
711#if PROTOCOL_VERSION < 719
713#elif PROTOCOL_VERSION < 764
719#if PROTOCOL_VERSION > 718
720#if PROTOCOL_VERSION < 751
723 const std::string& dim_name = d[
"name"].get<std::string>();
726#elif PROTOCOL_VERSION < 764
729 const std::string& dim_name = d[
"name"].get<std::string>();
731#if PROTOCOL_VERSION > 756
732 dimension_height[dim_name] =
static_cast<unsigned int>(d[
"element"][
"height"].get<
int>());
744 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
745#if PROTOCOL_VERSION < 719
747#elif PROTOCOL_VERSION < 764
753#if PROTOCOL_VERSION > 747 && PROTOCOL_VERSION < 759
755#if PROTOCOL_VERSION > 756
764 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
765#if PROTOCOL_VERSION < 347
767 unsigned char metadata;
768 Blockstate::IdToIdMetadata(msg.GetBlockstate(),
id, metadata);
777 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
778#if PROTOCOL_VERSION < 739
779 for (
size_t i = 0; i < msg.GetRecords().size(); ++i)
781 unsigned char x = (msg.GetRecords()[i].GetHorizontalPosition() >> 4) & 0x0F;
782 unsigned char z = msg.GetRecords()[i].GetHorizontalPosition() & 0x0F;
784 const int x_pos =
CHUNK_WIDTH * msg.GetChunkX() + x;
785 const int y_pos = msg.GetRecords()[i].GetYCoordinate();
786 const int z_pos =
CHUNK_WIDTH * msg.GetChunkZ() + z;
788 const int chunk_x =
CHUNK_WIDTH * (msg.GetSectionPos() >> 42);
789 const int chunk_z =
CHUNK_WIDTH * (msg.GetSectionPos() << 22 >> 42);
790 const int chunk_y =
SECTION_HEIGHT * (msg.GetSectionPos() << 44 >> 44);
792 for (
size_t i = 0; i < msg.GetPosState().size(); ++i)
794 const unsigned int block_id = msg.GetPosState()[i] >> 12;
795 const short position = msg.GetPosState()[i] & 0xFFFl;
797 const int x_pos = chunk_x + ((position >> 8) & 0xF);
798 const int z_pos = chunk_z + ((position >> 4) & 0xF);
799 const int y_pos = chunk_y + ((position >> 0) & 0xF);
801 Position cube_pos(x_pos, y_pos, z_pos);
804#if PROTOCOL_VERSION < 347
806 unsigned char metadata;
807 Blockstate::IdToIdMetadata(msg.GetRecords()[i].GetBlockId(),
id, metadata);
810#elif PROTOCOL_VERSION < 739
811 SetBlockImpl(cube_pos, msg.GetRecords()[i].GetBlockId());
821#if PROTOCOL_VERSION < 764
822 UnloadChunk(msg.GetX(), msg.GetZ(), std::this_thread::get_id());
824 UnloadChunk(msg.GetPos().GetX(), msg.GetPos().GetZ(), std::this_thread::get_id());
828#if PROTOCOL_VERSION < 757
829 void World::Handle(ProtocolCraft::ClientboundLevelChunkPacket& msg)
832#if PROTOCOL_VERSION < 755
833 if (msg.GetFullChunk())
837#if PROTOCOL_VERSION < 755
842 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
843#if PROTOCOL_VERSION > 404
844 if (
auto it = delayed_light_updates.find({ msg.GetX(), msg.GetZ() }); it != delayed_light_updates.end())
847 it->second.GetSkyYMask(), it->second.GetEmptySkyYMask(), it->second.GetSkyUpdates(),
true);
849 it->second.GetBlockYMask(), it->second.GetEmptyBlockYMask(), it->second.GetBlockUpdates(),
false);
850 delayed_light_updates.erase(it);
853#if PROTOCOL_VERSION < 552
854 LoadDataInChunk(msg.GetX(), msg.GetZ(), msg.GetBuffer(), msg.GetAvailableSections(), msg.GetFullChunk());
856 LoadDataInChunk(msg.GetX(), msg.GetZ(), msg.GetBuffer(), msg.GetAvailableSections());
857#if PROTOCOL_VERSION < 755
858 if (msg.GetBiomes().has_value())
860#if PROTOCOL_VERSION < 751
862 LoadBiomesInChunk(msg.GetX(), msg.GetZ(), std::vector<int>(msg.GetBiomes().value().begin(), msg.GetBiomes().value().end()));
864 LoadBiomesInChunk(msg.GetX(), msg.GetZ(), msg.GetBiomes().value());
868 LoadBiomesInChunk(msg.GetX(), msg.GetZ(), msg.GetBiomes());
877 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
879 LoadDataInChunk(msg.GetX(), msg.GetZ(), msg.GetChunkData().GetBuffer());
882 msg.GetLightData().GetSkyYMask(), msg.GetLightData().GetEmptySkyYMask(), msg.GetLightData().GetSkyUpdates(),
true);
884 msg.GetLightData().GetBlockYMask(), msg.GetLightData().GetEmptyBlockYMask(), msg.GetLightData().GetBlockUpdates(),
false);
888#if PROTOCOL_VERSION > 404
891 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
892#if PROTOCOL_VERSION < 757
895 delayed_light_updates[{msg.GetX(), msg.GetZ()}] = msg;
899 msg.GetSkyYMask(), msg.GetEmptySkyYMask(), msg.GetSkyUpdates(),
true);
901 msg.GetBlockYMask(), msg.GetEmptyBlockYMask(), msg.GetBlockUpdates(),
false);
904 msg.GetLightData().GetSkyYMask(), msg.GetLightData().GetEmptySkyYMask(), msg.GetLightData().GetSkyUpdates(),
true);
906 msg.GetLightData().GetBlockYMask(), msg.GetLightData().GetEmptyBlockYMask(), msg.GetLightData().GetBlockUpdates(),
false);
916#if PROTOCOL_VERSION > 761
919 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
920 for (
const auto& chunk_data : msg.GetChunkBiomeData())
922 auto it =
terrain.find({ chunk_data.GetPos().GetX(), chunk_data.GetPos().GetZ()});
925 it->second.LoadBiomesData(chunk_data.GetBuffer());
929 LOG_WARNING(
"Trying to load biomes data in non loaded chunk (" << chunk_data.GetPos().GetX() <<
", " << chunk_data.GetPos().GetZ() <<
")");
935#if PROTOCOL_VERSION > 763
938 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
939#if PROTOCOL_VERSION < 766
942 const std::string& dim_name = d[
"name"].get<std::string>();
943 dimension_height[dim_name] =
static_cast<unsigned int>(d[
"element"][
"height"].get<
int>());
948 if (msg.GetRegistry().GetFull() !=
"minecraft:dimension_type")
953 const auto& entries = msg.GetEntries();
954 for (
size_t i = 0; i < entries.size(); ++i)
956 const std::string dim_name = entries[i].
GetId().GetFull();
962 if (entries[i].GetData().has_value())
974#if PROTOCOL_VERSION < 719
975 void World::LoadChunkImpl(
const int x,
const int z,
const Dimension dim,
const std::thread::id& loader_id)
980#if PROTOCOL_VERSION < 719
981 const bool has_sky_light = dim == Dimension::Overworld;
983 const bool has_sky_light = dim ==
"minecraft:overworld";
986 auto it =
terrain.find({ x,z });
989#if PROTOCOL_VERSION < 757
990 auto inserted =
terrain.insert({ {x, z},
Chunk(dim_index, has_sky_light) });
994 inserted.first->second.AddLoader(loader_id);
997 else if (it->second.GetDimensionIndex() != dim_index)
1001 LOG_WARNING(
"Changing dimension with a shared world is not supported and can lead to wrong world data");
1004#if PROTOCOL_VERSION < 757
1005 it->second =
Chunk(dim_index, has_sky_light);
1009 it->second.AddLoader(loader_id);
1013 it->second.AddLoader(loader_id);
1022 auto it =
terrain.find({ x, z });
1025 const size_t load_counter = it->second.RemoveLoader(loader_id);
1026 if (load_counter == 0)
1038 const int chunk_x =
static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH)));
1039 const int chunk_z =
static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)));
1041 auto it =
terrain.find({ chunk_x, chunk_z });
1055 it->second.SetBlock(set_pos,
id);
1065 const int chunk_x =
static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH)));
1066 const int chunk_z =
static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)));
1068 auto it =
terrain.find({ chunk_x, chunk_z });
1082 const Blockstate* output = it->second.GetBlock(chunk_pos);
1087 return output !=
nullptr ?
1089#if PROTOCOL_VERSION < 347
1096#if PROTOCOL_VERSION < 719
1103#if PROTOCOL_VERSION > 404 && PROTOCOL_VERSION < 757
1104 delayed_light_updates.clear();
1110#if PROTOCOL_VERSION < 757
1119#if PROTOCOL_VERSION < 757
1126#if PROTOCOL_VERSION < 358
1128#elif PROTOCOL_VERSION < 552
1135 static_cast<int>(std::floor(x /
static_cast<double>(
CHUNK_WIDTH))),
1136 static_cast<int>(std::floor(z /
static_cast<double>(
CHUNK_WIDTH)))
1141#if PROTOCOL_VERSION < 552
1152 const Position this_chunk_position(
1158 if (this_chunk_position.
x > 0 && this_chunk_position.
x <
CHUNK_WIDTH - 1 &&
1159 this_chunk_position.
z > 0 && this_chunk_position.
z <
CHUNK_WIDTH - 1)
1166 if (chunk ==
nullptr)
1169 LOG_WARNING(
"Trying to propagate chunk updates from a non loaded chunk");
1175 if (this_chunk_position.
x == 0)
1178 if (neighbour_chunk !=
nullptr)
1187 if (neighbour_chunk !=
nullptr)
1189 neighbour_chunk->
SetBlock(
Position(-1, this_chunk_position.
y, this_chunk_position.
z), blockstate);
1193 if (this_chunk_position.
z == 0)
1196 if (neighbour_chunk !=
nullptr)
1205 if (neighbour_chunk !=
nullptr)
1207 neighbour_chunk->
SetBlock(
Position(this_chunk_position.
x, this_chunk_position.
y, -1), blockstate);
1219 if (chunk !=
nullptr)
1230 Chunk* neighbour_chunk;
1231 neighbour_chunk =
GetChunk(x - 1, z);
1232 if (neighbour_chunk !=
nullptr)
1236 neighbour_chunk =
GetChunk(x + 1, z);
1237 if (neighbour_chunk !=
nullptr)
1241 neighbour_chunk =
GetChunk(x, z - 1);
1242 if (neighbour_chunk !=
nullptr)
1246 neighbour_chunk =
GetChunk(x, z + 1);
1247 if (neighbour_chunk !=
nullptr)
1257 auto it =
terrain.find({ x,z });
1265#if PROTOCOL_VERSION < 552
1267 const int primary_bit_mask,
const bool ground_up_continuous)
1268#elif PROTOCOL_VERSION < 755
1270 const int primary_bit_mask)
1271#elif PROTOCOL_VERSION < 757
1273 const std::vector<unsigned long long int>& primary_bit_mask)
1278 auto it =
terrain.find({ x,z });
1281#if PROTOCOL_VERSION < 552
1282 it->second.
LoadChunkData(data, primary_bit_mask, ground_up_continuous);
1283#elif PROTOCOL_VERSION < 757
1284 it->second.LoadChunkData(data, primary_bit_mask);
1286 it->second.LoadChunkData(data);
1294#if PROTOCOL_VERSION < 757
1300 auto it =
terrain.find({ x,z });
1303 it->second.LoadChunkBlockEntitiesData(block_entities);
1307#if PROTOCOL_VERSION > 551 && PROTOCOL_VERSION < 757
1308 void World::LoadBiomesInChunk(
const int x,
const int z,
const std::vector<int>& biomes)
1310 auto it =
terrain.find({ x,z });
1313 it->second.SetBiomes(biomes);
1318#if PROTOCOL_VERSION > 404
1319#if PROTOCOL_VERSION < 719
1320 void World::UpdateChunkLight(
const int x,
const int z,
const Dimension dim,
const int light_mask,
const int empty_light_mask,
1321 const std::vector<std::vector<char>>& data,
const bool sky)
1322#elif PROTOCOL_VERSION < 755
1323 void World::UpdateChunkLight(
const int x,
const int z,
const std::string& dim,
const int light_mask,
const int empty_light_mask,
1324 const std::vector<std::vector<char>>& data,
const bool sky)
1327 const std::vector<unsigned long long int>& light_mask,
const std::vector<unsigned long long int>& empty_light_mask,
1328 const std::vector<std::vector<char>>& data,
const bool sky)
1331 auto it =
terrain.find({ x, z });
1335 LOG_WARNING(
"Trying to update lights in an unloaded chunk: (" << x <<
"," << z <<
")");
1339 int counter_arrays = 0;
1344 for (
int i = 0; i < num_sections; ++i)
1346 const int section_Y = i - 1;
1349#if PROTOCOL_VERSION < 755
1350 if ((light_mask >> i) & 1)
1352 if ((light_mask.size() > i / 64) && (light_mask[i / 64] >> (i % 64)) & 1)
1355 if (i > 0 && i < num_sections - 1)
1361 for (
int block_z = 0; block_z <
CHUNK_WIDTH; ++block_z)
1365 for (
int block_x = 0; block_x <
CHUNK_WIDTH; block_x += 2)
1368 pos2.
x = block_x + 1;
1373 it->second.SetSkyLight(pos1, two_light_values & 0x0F);
1374 it->second.SetSkyLight(pos2, (two_light_values >> 4) & 0x0F);
1378 it->second.SetBlockLight(pos1, two_light_values & 0x0F);
1379 it->second.SetBlockLight(pos2, (two_light_values >> 4) & 0x0F);
1387#if PROTOCOL_VERSION < 755
1388 else if ((empty_light_mask >> i) & 1)
1390 else if ((empty_light_mask.size() > i / 64) && (empty_light_mask[i / 64] >> (i % 64)) & 1)
1393 if (i > 0 && i < num_sections - 1)
1399 for (
int block_z = 0; block_z <
CHUNK_WIDTH; ++block_z)
1403 for (
int block_x = 0; block_x <
CHUNK_WIDTH; block_x += 2)
1406 pos2.
x = block_x + 1;
1409 it->second.SetSkyLight(pos1, 0);
1410 it->second.SetSkyLight(pos2, 0);
1414 it->second.SetBlockLight(pos1, 0);
1415 it->second.SetBlockLight(pos2, 0);
1426#if PROTOCOL_VERSION < 719
#define LOG_WARNING(osstream)
const Vector3< double > & GetHalfSize() const
Vector3< double > GetMin() const
const Vector3< double > & GetCenter() const
bool Collide(const AABB &b) const
Vector3< double > GetMax() const
static AssetsManager & getInstance()
const Blockstate * GetBlockstate(const BlockstateId id) const
bool IsWaterOrWaterlogged() const
bool IsFluidOrWaterlogged() const
std::set< AABB > GetCollidersAtPos(const Position &pos) const
bool IsFluidFalling() const
float GetFluidHeight() const
Get fluid height for this block.
void UpdateNeighbour(Chunk *const neighbour, const Orientation direction)
void LoadChunkData(const std::vector< unsigned char > &data)
const Blockstate * GetBlock(const Position &pos) const
void SetBlock(const Position &pos, const Blockstate *block)
Mutex protected reference, will be locked until destroyed.
void SetBlockEntityData(const Position &pos, const ProtocolCraft::NBT::Value &data)
Set block entity data at pos.
Vector3< double > GetFlow(const Position &pos)
Get the flow of fluid at a given position.
void UnloadChunkImpl(const int x, const int z, const std::thread::id &loader_id)
void SetSkyLight(const Position &pos, const unsigned char skylight)
Set sky light value.
std::unordered_map< std::pair< int, int >, Chunk > terrain
void UnloadChunk(const int x, const int z, const std::thread::id &loader_id=std::this_thread::get_id())
Remove a chunk at given coordinates.
unsigned char GetBlockLight(const Position &pos) const
Get block light value.
const Blockstate * GetBlock(const Position &pos) const
Get the blockstate at a given position.
bool IsFree(const AABB &aabb, const bool fluid_collide) const
Check if an AABB collides in the world.
std::optional< Chunk > ResetChunkModificationState(const int x, const int z)
Reset a chunk modification state.
void SetDimensionMinY(const std::string &dimension, const int min_y)
Set min block for given dimension.
void SetDimensionUltrawarm(const std::string &dimension, const bool ultrawarm)
Set ultrawarm bool for given dimension.
void LoadDataInChunk(const int x, const int z, const std::vector< unsigned char > &data)
void SetCurrentDimensionImpl(const std::string &dimension)
Chunk * GetChunk(const int x, const int z)
Get a pointer to a chunk.
void UpdateChunkLight(const int x, const int z, const std::string &dim, const std::vector< unsigned long long int > &light_mask, const std::vector< unsigned long long int > &empty_light_mask, const std::vector< std::vector< char > > &data, const bool sky)
int GetNextWorldInteractionSequenceId()
Get a unique id used for server interactions.
void LoadChunk(const int x, const int z, const std::string &dim, const std::thread::id &loader_id=std::this_thread::get_id())
Add a chunk at given coordinates.
std::unordered_map< std::string, size_t > dimension_index_map
std::string current_dimension
std::unordered_map< size_t, std::string > index_dimension_map
bool HasChunkBeenModified(const int x, const int z)
Check if a chunk modification flag is set.
bool IsInUltraWarmDimension() const
Check if current dimension is Ultrawarm.
void UpdateChunk(const int chunk_x, const int chunk_z, const Position &pos)
Progagate chunk update at pos to neighbouring chunks.
void SetDimensionHeight(const std::string &dimension, const int height)
Set total height for given dimension.
int GetHeight() const
Get height of the current dimension.
std::unordered_map< std::string, unsigned int > dimension_height
Height of the chunks in a given dimension.
const Biome * GetBiome(const Position &pos) const
Get the biome at a given position.
const Blockstate * GetBlockImpl(const Position &pos) const
void SetCurrentDimension(const std::string &dimension)
Set current world dimension.
void SetBlock(const Position &pos, const BlockstateId id)
Set block at given pos.
void SetBlockImpl(const Position &pos, const BlockstateId id)
bool IsLoaded(const Position &pos) const
Check if a position is in a loaded chunk.
ProtocolCraft::NBT::Value GetBlockEntityData(const Position &pos) const
Get the block entity data at a given position.
World(const bool is_shared_)
std::atomic< int > world_interaction_sequence_id
void UnloadAllChunks(const std::thread::id &loader_id=std::this_thread::get_id())
Remove all chunks from memory.
int GetHeightImpl() const
virtual void Handle(ProtocolCraft::ClientboundLoginPacket &msg) override
void SetBiomeImpl(const int x, const int y, const int z, const int biome)
std::vector< AABB > GetColliders(const AABB &aabb, const Vector3< double > &movement=Vector3< double >(0.0)) const
Get all colliders that could collide with a given AABB.
void SetBlockLight(const Position &pos, const unsigned char blocklight)
Set block light value.
std::unordered_map< std::string, bool > dimension_ultrawarm
std::unordered_map< std::string, int > dimension_min_y
Height of the lowest block in a given dimension.
const Blockstate * Raycast(const Vector3< double > &origin, const Vector3< double > &direction, const float max_radius, Position &out_pos, Position &out_normal)
Perform a raycast in the voxel world and return position, normal and blockstate which are hit.
void SetBiome(const int x, const int y, const int z, const int biome)
Set biome of given block.
void LoadBlockEntityDataInChunk(const int x, const int z, const std::vector< ProtocolCraft::BlockEntityInfo > &block_entities)
unsigned char GetSkyLight(const Position &pos) const
Get sky light value.
size_t GetDimIndex(const std::string &dim)
bool IsShared() const
is_shared getter
std::optional< Position > GetSupportingBlockPos(const AABB &aabb) const
Get the block position supporting an aabb.
void LoadChunkImpl(const int x, const int z, const std::string &dim, const std::thread::id &loader_id)
int GetMinY() const
Get min_y of the current dimension.
std::shared_mutex world_mutex
std::vector< const Blockstate * > GetBlocks(const std::vector< Position > &pos) const
Get blockstates for a set of positions.
Utilities::ScopeLockedWrapper< const std::unordered_map< std::pair< int, int >, Chunk >, std::shared_mutex, std::shared_lock > GetChunks() const
Get a read-only locked version of all the loaded chunks.
std::string GetCurrentDimension() const
Get current world dimension.
std::string GetDimension(const int x, const int z) const
Get dimension of chunk at given coordinates.
virtual int GetId() const override
static constexpr int SECTION_HEIGHT
static constexpr int CHUNK_WIDTH
unsigned int BlockstateId
double SqrDist(const Vector3 &v) const