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(packet.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 < packet.GetRecords().size(); ++i)
781 unsigned char x = (packet.GetRecords()[i].GetHorizontalPosition() >> 4) & 0x0F;
782 unsigned char z = packet.GetRecords()[i].GetHorizontalPosition() & 0x0F;
784 const int x_pos =
CHUNK_WIDTH * packet.GetChunkX() + x;
785 const int y_pos = packet.GetRecords()[i].GetYCoordinate();
786 const int z_pos =
CHUNK_WIDTH * packet.GetChunkZ() + z;
788 const int chunk_x =
CHUNK_WIDTH * (packet.GetSectionPos() >> 42);
789 const int chunk_z =
CHUNK_WIDTH * (packet.GetSectionPos() << 22 >> 42);
790 const int chunk_y =
SECTION_HEIGHT * (packet.GetSectionPos() << 44 >> 44);
792 for (
size_t i = 0; i < packet.GetPosState().size(); ++i)
794 const unsigned int block_id = packet.GetPosState()[i] >> 12;
795 const short position = packet.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(packet.GetRecords()[i].GetBlockId(),
id, metadata);
810#elif PROTOCOL_VERSION < 739
811 SetBlockImpl(cube_pos, packet.GetRecords()[i].GetBlockId());
821#if PROTOCOL_VERSION < 764
822 UnloadChunk(packet.GetX(), packet.GetZ(), std::this_thread::get_id());
824 UnloadChunk(packet.GetPos().GetX(), packet.GetPos().GetZ(), std::this_thread::get_id());
828#if PROTOCOL_VERSION < 757
829 void World::Handle(ProtocolCraft::ClientboundLevelChunkPacket& packet)
832#if PROTOCOL_VERSION < 755
833 if (packet.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({ packet.GetX(), packet.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(packet.GetX(), packet.GetZ(), packet.GetBuffer(), packet.GetAvailableSections(), packet.GetFullChunk());
856 LoadDataInChunk(packet.GetX(), packet.GetZ(), packet.GetBuffer(), packet.GetAvailableSections());
857#if PROTOCOL_VERSION < 755
858 if (packet.GetBiomes().has_value())
860#if PROTOCOL_VERSION < 751
862 LoadBiomesInChunk(packet.GetX(), packet.GetZ(), std::vector<int>(packet.GetBiomes().value().begin(), packet.GetBiomes().value().end()));
864 LoadBiomesInChunk(packet.GetX(), packet.GetZ(), packet.GetBiomes().value());
868 LoadBiomesInChunk(packet.GetX(), packet.GetZ(), packet.GetBiomes());
877 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
879 LoadDataInChunk(packet.GetX(), packet.GetZ(), packet.GetChunkData().GetBuffer());
882 packet.GetLightData().GetSkyYMask(), packet.GetLightData().GetEmptySkyYMask(), packet.GetLightData().GetSkyUpdates(),
true);
884 packet.GetLightData().GetBlockYMask(), packet.GetLightData().GetEmptyBlockYMask(), packet.GetLightData().GetBlockUpdates(),
false);
888#if PROTOCOL_VERSION > 404
891 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
892#if PROTOCOL_VERSION < 757
893 if (
terrain.find({ packet.GetX(), packet.GetZ() }) ==
terrain.end())
895 delayed_light_updates[{packet.GetX(), packet.GetZ()}] = packet;
899 packet.GetSkyYMask(), packet.GetEmptySkyYMask(), packet.GetSkyUpdates(),
true);
901 packet.GetBlockYMask(), packet.GetEmptyBlockYMask(), packet.GetBlockUpdates(),
false);
904 packet.GetLightData().GetSkyYMask(), packet.GetLightData().GetEmptySkyYMask(), packet.GetLightData().GetSkyUpdates(),
true);
906 packet.GetLightData().GetBlockYMask(), packet.GetLightData().GetEmptyBlockYMask(), packet.GetLightData().GetBlockUpdates(),
false);
916#if PROTOCOL_VERSION > 761
919 std::scoped_lock<std::shared_mutex> lock(
world_mutex);
920 for (
const auto& chunk_data : packet.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 (packet.GetRegistry().GetFull() !=
"minecraft:dimension_type")
953 const auto& entries = packet.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())
967#if PROTOCOL_VERSION < 774
970 dimension_fast_lava[dim_name] =
static_cast<bool>(data[
"attributes"].
contains(
"minecraft:gameplay/fast_lava") && data[
"attributes"][
"minecraft:gameplay/fast_lava"].
get<
char>());
978#if PROTOCOL_VERSION < 719
979 void World::LoadChunkImpl(
const int x,
const int z,
const Dimension dim,
const std::thread::id& loader_id)
984#if PROTOCOL_VERSION < 719
985 const bool has_sky_light = dim == Dimension::Overworld;
987 const bool has_sky_light = dim ==
"minecraft:overworld";
990 auto it =
terrain.find({ x,z });
993#if PROTOCOL_VERSION < 757
994 auto inserted =
terrain.insert({ {x, z},
Chunk(dim_index, has_sky_light) });
998 inserted.first->second.AddLoader(loader_id);
1001 else if (it->second.GetDimensionIndex() != dim_index)
1005 LOG_WARNING(
"Changing dimension with a shared world is not supported and can lead to wrong world data");
1008#if PROTOCOL_VERSION < 757
1009 it->second =
Chunk(dim_index, has_sky_light);
1013 it->second.AddLoader(loader_id);
1017 it->second.AddLoader(loader_id);
1026 auto it =
terrain.find({ x, z });
1029 const size_t load_counter = it->second.RemoveLoader(loader_id);
1030 if (load_counter == 0)
1042 const int chunk_x =
static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH)));
1043 const int chunk_z =
static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)));
1045 auto it =
terrain.find({ chunk_x, chunk_z });
1059 it->second.SetBlock(set_pos,
id);
1069 const int chunk_x =
static_cast<int>(std::floor(pos.
x /
static_cast<double>(
CHUNK_WIDTH)));
1070 const int chunk_z =
static_cast<int>(std::floor(pos.
z /
static_cast<double>(
CHUNK_WIDTH)));
1072 auto it =
terrain.find({ chunk_x, chunk_z });
1086 const Blockstate* output = it->second.GetBlock(chunk_pos);
1091 return output !=
nullptr ?
1093#if PROTOCOL_VERSION < 347
1100#if PROTOCOL_VERSION < 719
1107#if PROTOCOL_VERSION > 404 && PROTOCOL_VERSION < 757
1108 delayed_light_updates.clear();
1114#if PROTOCOL_VERSION < 757
1123#if PROTOCOL_VERSION < 757
1130#if PROTOCOL_VERSION < 358
1132#elif PROTOCOL_VERSION < 552
1139 static_cast<int>(std::floor(x /
static_cast<double>(
CHUNK_WIDTH))),
1140 static_cast<int>(std::floor(z /
static_cast<double>(
CHUNK_WIDTH)))
1145#if PROTOCOL_VERSION < 552
1156 const Position this_chunk_position(
1162 if (this_chunk_position.
x > 0 && this_chunk_position.
x <
CHUNK_WIDTH - 1 &&
1163 this_chunk_position.
z > 0 && this_chunk_position.
z <
CHUNK_WIDTH - 1)
1170 if (chunk ==
nullptr)
1173 LOG_WARNING(
"Trying to propagate chunk updates from a non loaded chunk");
1179 if (this_chunk_position.
x == 0)
1182 if (neighbour_chunk !=
nullptr)
1191 if (neighbour_chunk !=
nullptr)
1193 neighbour_chunk->
SetBlock(
Position(-1, this_chunk_position.
y, this_chunk_position.
z), blockstate);
1197 if (this_chunk_position.
z == 0)
1200 if (neighbour_chunk !=
nullptr)
1209 if (neighbour_chunk !=
nullptr)
1211 neighbour_chunk->
SetBlock(
Position(this_chunk_position.
x, this_chunk_position.
y, -1), blockstate);
1223 if (chunk !=
nullptr)
1234 Chunk* neighbour_chunk;
1235 neighbour_chunk =
GetChunk(x - 1, z);
1236 if (neighbour_chunk !=
nullptr)
1240 neighbour_chunk =
GetChunk(x + 1, z);
1241 if (neighbour_chunk !=
nullptr)
1245 neighbour_chunk =
GetChunk(x, z - 1);
1246 if (neighbour_chunk !=
nullptr)
1250 neighbour_chunk =
GetChunk(x, z + 1);
1251 if (neighbour_chunk !=
nullptr)
1261 auto it =
terrain.find({ x,z });
1269#if PROTOCOL_VERSION < 552
1271 const int primary_bit_mask,
const bool ground_up_continuous)
1272#elif PROTOCOL_VERSION < 755
1274 const int primary_bit_mask)
1275#elif PROTOCOL_VERSION < 757
1277 const std::vector<unsigned long long int>& primary_bit_mask)
1282 auto it =
terrain.find({ x,z });
1285#if PROTOCOL_VERSION < 552
1286 it->second.
LoadChunkData(data, primary_bit_mask, ground_up_continuous);
1287#elif PROTOCOL_VERSION < 757
1288 it->second.LoadChunkData(data, primary_bit_mask);
1290 it->second.LoadChunkData(data);
1298#if PROTOCOL_VERSION < 757
1304 auto it =
terrain.find({ x,z });
1307 it->second.LoadChunkBlockEntitiesData(block_entities);
1311#if PROTOCOL_VERSION > 551 && PROTOCOL_VERSION < 757
1312 void World::LoadBiomesInChunk(
const int x,
const int z,
const std::vector<int>& biomes)
1314 auto it =
terrain.find({ x,z });
1317 it->second.SetBiomes(biomes);
1322#if PROTOCOL_VERSION > 404
1323#if PROTOCOL_VERSION < 719
1324 void World::UpdateChunkLight(
const int x,
const int z,
const Dimension dim,
const int light_mask,
const int empty_light_mask,
1325 const std::vector<std::vector<char>>& data,
const bool sky)
1326#elif PROTOCOL_VERSION < 755
1327 void World::UpdateChunkLight(
const int x,
const int z,
const std::string& dim,
const int light_mask,
const int empty_light_mask,
1328 const std::vector<std::vector<char>>& data,
const bool sky)
1331 const std::vector<unsigned long long int>& light_mask,
const std::vector<unsigned long long int>& empty_light_mask,
1332 const std::vector<std::vector<char>>& data,
const bool sky)
1335 auto it =
terrain.find({ x, z });
1339 LOG_WARNING(
"Trying to update lights in an unloaded chunk: (" << x <<
"," << z <<
")");
1343 int counter_arrays = 0;
1348 for (
int i = 0; i < num_sections; ++i)
1350 const int section_Y = i - 1;
1353#if PROTOCOL_VERSION < 755
1354 if ((light_mask >> i) & 1)
1356 if ((light_mask.size() > i / 64) && (light_mask[i / 64] >> (i % 64)) & 1)
1359 if (i > 0 && i < num_sections - 1)
1365 for (
int block_z = 0; block_z <
CHUNK_WIDTH; ++block_z)
1369 for (
int block_x = 0; block_x <
CHUNK_WIDTH; block_x += 2)
1372 pos2.
x = block_x + 1;
1377 it->second.SetSkyLight(pos1, two_light_values & 0x0F);
1378 it->second.SetSkyLight(pos2, (two_light_values >> 4) & 0x0F);
1382 it->second.SetBlockLight(pos1, two_light_values & 0x0F);
1383 it->second.SetBlockLight(pos2, (two_light_values >> 4) & 0x0F);
1391#if PROTOCOL_VERSION < 755
1392 else if ((empty_light_mask >> i) & 1)
1394 else if ((empty_light_mask.size() > i / 64) && (empty_light_mask[i / 64] >> (i % 64)) & 1)
1397 if (i > 0 && i < num_sections - 1)
1403 for (
int block_z = 0; block_z <
CHUNK_WIDTH; ++block_z)
1407 for (
int block_x = 0; block_x <
CHUNK_WIDTH; block_x += 2)
1410 pos2.
x = block_x + 1;
1413 it->second.SetSkyLight(pos1, 0);
1414 it->second.SetSkyLight(pos2, 0);
1418 it->second.SetBlockLight(pos1, 0);
1419 it->second.SetBlockLight(pos2, 0);
1430#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 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 SetDimensionFastLava(const std::string &dimension, const bool fast_lava)
Set fast lava bool for given dimension.
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
bool IsInFastLavaDimension() const
Check if current dimension has fast lava.
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.
void UpdateChunk(const int chunk_x, const int chunk_z, const Position &pos)
Progagate chunk update at pos to neighbouring chunks.
virtual void Handle(ProtocolCraft::ClientboundLoginPacket &packet) override
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.
std::unordered_map< std::string, bool > dimension_fast_lava
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
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, 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
bool contains(const std::string &s) const
static constexpr int SECTION_HEIGHT
static constexpr int CHUNK_WIDTH
unsigned int BlockstateId
double SqrDist(const Vector3 &v) const