From e5fd062a4a2c22220b697816fb3a30322799cc79 Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Fri, 7 May 2021 00:14:25 +0000 Subject: [PATCH] Handle loading / unloading chunks better --- mosfet/bot.py | 8 +++----- mosfet/commands.py | 4 +++- mosfet/game.py | 7 ++++++- mosfet/monkey_patch.py | 1 + mosfet/protocol/managers.py | 34 +++++++++++++--------------------- mosfet/protocol/packets.py | 32 ++++++++++++++++++++++---------- 6 files changed, 48 insertions(+), 38 deletions(-) diff --git a/mosfet/bot.py b/mosfet/bot.py index 885d1bf..410634e 100644 --- a/mosfet/bot.py +++ b/mosfet/bot.py @@ -65,21 +65,19 @@ def tick(global_state): target = None # make sure current chunks are loaded for physics - if not g.chunks.check_loaded(p, 288): + if not g.chunks.check_loaded(g.info.render_distance): if not g.chunks.loading: print('Loading chunks', end='', flush=True) - g.chunks.loading = True + g.chunks.loading = time.time() packet = serverbound.play.PositionAndLookPacket(x=p.x, feet_y=p.y, z=p.z, pitch=0, yaw=0, on_ground=True) g.connection.write_packet(packet, force=True) return else: if g.chunks.loading: print() - print('Chunks loaded.') + print('Chunks loaded in', round(time.time() - g.chunks.loading, 2), 's') g.chunks.loading = False - g.chunks.unload_chunks(p) - ########## object physics ########## # note: it's possible the chunk data is out of date when this runs diff --git a/mosfet/commands.py b/mosfet/commands.py index b4dd138..5771f7f 100644 --- a/mosfet/commands.py +++ b/mosfet/commands.py @@ -149,7 +149,9 @@ class Commands: ## !loaded - replies with the current loaded area if command == 'loaded': - reply = str(self.g.chunks.get_loaded_area()) + l = self.g.chunks.get_loaded_area() + reply = '{}, {}, {} to {}, {}, {}'.format(*l[0], *l[1]) + reply += ' - ' + str(len(self.g.chunks.chunks)//16) + ' chunks' ## !players - prints the current players ## !players clear - clears the current player list diff --git a/mosfet/game.py b/mosfet/game.py index f484505..43f34d1 100644 --- a/mosfet/game.py +++ b/mosfet/game.py @@ -15,7 +15,7 @@ from mosfet.protocol.packets import ( ClientWindowConfirmationPacket, EntityMetadataPacket, SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket, EntityActionPacket, EntityTeleport, InteractEntityPacket, TradeListPacket, - SelectTradePacket, DisconnectPacket, + SelectTradePacket, DisconnectPacket, UnloadChunkPacket, ) from mosfet.protocol.types import Slot @@ -58,6 +58,7 @@ class Game: #register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket) register(self.handle_trade_list, TradeListPacket) register(self.handle_disconnect, DisconnectPacket) + register(self.handle_unload_chunk, UnloadChunkPacket) #register(self.handle_packet, Packet, early=True) @@ -486,6 +487,7 @@ class Game: def handle_respawn(self, packet): print(packet) self.g.dimension = packet.world_name.replace('minecraft:', '') + self.g.chunks.unload_all_chunks() def handle_player_list(self, packet): for action in packet.actions: @@ -532,6 +534,9 @@ class Game: import os os._exit(1) + def handle_unload_chunk(self, packet): + self.g.chunks.unload_chunk(packet.chunk_x, packet.chunk_z) + def tick(self): if self.g.breaking: self.animate() diff --git a/mosfet/monkey_patch.py b/mosfet/monkey_patch.py index de2a6ca..088e35d 100644 --- a/mosfet/monkey_patch.py +++ b/mosfet/monkey_patch.py @@ -20,6 +20,7 @@ def get_packets(old_get_packets): mc_packets.add(packets.EntityTeleport) mc_packets.add(packets.TradeListPacket) mc_packets.add(packets.DisconnectPacket) + mc_packets.add(packets.UnloadChunkPacket) return mc_packets diff --git a/mosfet/protocol/managers.py b/mosfet/protocol/managers.py index e33d5db..b615699 100644 --- a/mosfet/protocol/managers.py +++ b/mosfet/protocol/managers.py @@ -70,7 +70,6 @@ class ChunksManager: for item_id, locations in chunk.sub_index.items(): if item_id not in self.index: self.index[item_id] = [] - for l in locations: coords = (dx + l%16, dy + l//256, dz + l%256//16) self.index[item_id].append(coords) @@ -122,28 +121,21 @@ class ChunksManager: self.index[block] = [] self.index[block].append((x, y, z)) - def check_loaded(self, position, steps=1): - x, y, z = utils.pint(position) - player_chunk = (x//16, 1, z//16) - for i in range(steps): # TODO: base off render_distance? - offset = utils.spiral(i) - check = utils.padd(player_chunk, offset) + def check_loaded(self, chunk_distance): + num = (chunk_distance * 2 + 1) ** 2 + num_subchunks = num * 16 + return len(self.chunks) >= num_subchunks - if check not in self.chunks: - return False - - return True - - def unload_chunks(self, position): - x, y, z = utils.pint(position) - player_chunk = (x//16, 0, z//16) - loaded_chunks = list(self.chunks.keys()) - - for chunk in loaded_chunks: - check = (chunk[0], 0, chunk[2]) - if utils.phyp_king(player_chunk, check) > 20: - del self.chunks[chunk] + def unload_chunk(self, x, z): + for y in range(16): + try: + del self.chunks[(x, y, z)] + except KeyError: + pass + def unload_all_chunks(self): + self.chunks = {} + self.index = {} class ChunkNotLoadedException(Exception): def __str__(self): diff --git a/mosfet/protocol/packets.py b/mosfet/protocol/packets.py index f8b3a50..8886c8d 100644 --- a/mosfet/protocol/packets.py +++ b/mosfet/protocol/packets.py @@ -31,10 +31,10 @@ class ChunkDataPacket(Packet): self.biomes.append(VarInt.read(file_object)) size = VarInt.read(file_object) self.data = file_object.read(size) - size_entities = VarInt.read(file_object) - self.entities = [] - for i in range(size_entities): - self.entities.append(Nbt.read(file_object)) + #size_entities = VarInt.read(file_object) + #self.entities = [] + #for i in range(size_entities): + # self.entities.append(Nbt.read(file_object)) self.decode_chunk_data() @@ -49,9 +49,9 @@ class ChunkDataPacket(Packet): Integer.send(self.biomes[i], packet_buffer) VarInt.send(len(self.data), packet_buffer) packet_buffer.send(self.data) - VarInt.send(len(self.entities), packet_buffer) - for e in self.entities: - Nbt.send(e, packet_buffer) + #VarInt.send(len(self.entities), packet_buffer) + #for e in self.entities: + # Nbt.send(e, packet_buffer) def decode_chunk_data(self): packet_data = PacketBuffer() @@ -64,9 +64,9 @@ class ChunkDataPacket(Packet): if self.bit_mask_y & (1 << i): self.chunks[i].read(packet_data) - for e in self.entities: - y = e['y'] - self.chunks[floor(y/16)].entities.append(e) + #for e in self.entities: + # y = e['y'] + # self.chunks[floor(y/16)].entities.append(e) class Chunk: position = multi_attribute_alias(Vector, 'x', 'y', 'z') @@ -458,3 +458,15 @@ class DisconnectPacket(Packet): definition = [ {'reason': String}, ] + +class UnloadChunkPacket(Packet): + # Tells the client to unload a chunk column + # https://wiki.vg/Protocol#Unload_Chunk + + id = 0x1C + packet_name = 'unload chunk' + + definition = [ + {'chunk_x': Integer}, + {'chunk_z': Integer}, + ]