Handle loading / unloading chunks better
This commit is contained in:
		@@ -65,21 +65,19 @@ def tick(global_state):
 | 
				
			|||||||
    target = None
 | 
					    target = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # make sure current chunks are loaded for physics
 | 
					    # 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:
 | 
					        if not g.chunks.loading:
 | 
				
			||||||
            print('Loading chunks', end='', flush=True)
 | 
					            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)
 | 
					        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)
 | 
					        g.connection.write_packet(packet, force=True)
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        if g.chunks.loading:
 | 
					        if g.chunks.loading:
 | 
				
			||||||
            print()
 | 
					            print()
 | 
				
			||||||
            print('Chunks loaded.')
 | 
					            print('Chunks loaded in', round(time.time() - g.chunks.loading, 2), 's')
 | 
				
			||||||
        g.chunks.loading = False
 | 
					        g.chunks.loading = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g.chunks.unload_chunks(p)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ########## object physics ##########
 | 
					    ########## object physics ##########
 | 
				
			||||||
    # note: it's possible the chunk data is out of date when this runs
 | 
					    # note: it's possible the chunk data is out of date when this runs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -149,7 +149,9 @@ class Commands:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            ## !loaded - replies with the current loaded area
 | 
					            ## !loaded - replies with the current loaded area
 | 
				
			||||||
            if command == 'loaded':
 | 
					            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 - prints the current players
 | 
				
			||||||
            ## !players clear - clears the current player list
 | 
					            ## !players clear - clears the current player list
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ from mosfet.protocol.packets import (
 | 
				
			|||||||
    ClientWindowConfirmationPacket, EntityMetadataPacket,
 | 
					    ClientWindowConfirmationPacket, EntityMetadataPacket,
 | 
				
			||||||
    SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket,
 | 
					    SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket,
 | 
				
			||||||
    EntityActionPacket, EntityTeleport, InteractEntityPacket, TradeListPacket,
 | 
					    EntityActionPacket, EntityTeleport, InteractEntityPacket, TradeListPacket,
 | 
				
			||||||
    SelectTradePacket, DisconnectPacket,
 | 
					    SelectTradePacket, DisconnectPacket, UnloadChunkPacket,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from mosfet.protocol.types import Slot
 | 
					from mosfet.protocol.types import Slot
 | 
				
			||||||
@@ -58,6 +58,7 @@ class Game:
 | 
				
			|||||||
        #register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket)
 | 
					        #register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket)
 | 
				
			||||||
        register(self.handle_trade_list, TradeListPacket)
 | 
					        register(self.handle_trade_list, TradeListPacket)
 | 
				
			||||||
        register(self.handle_disconnect, DisconnectPacket)
 | 
					        register(self.handle_disconnect, DisconnectPacket)
 | 
				
			||||||
 | 
					        register(self.handle_unload_chunk, UnloadChunkPacket)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #register(self.handle_packet, Packet, early=True)
 | 
					        #register(self.handle_packet, Packet, early=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -486,6 +487,7 @@ class Game:
 | 
				
			|||||||
    def handle_respawn(self, packet):
 | 
					    def handle_respawn(self, packet):
 | 
				
			||||||
        print(packet)
 | 
					        print(packet)
 | 
				
			||||||
        self.g.dimension = packet.world_name.replace('minecraft:', '')
 | 
					        self.g.dimension = packet.world_name.replace('minecraft:', '')
 | 
				
			||||||
 | 
					        self.g.chunks.unload_all_chunks()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def handle_player_list(self, packet):
 | 
					    def handle_player_list(self, packet):
 | 
				
			||||||
        for action in packet.actions:
 | 
					        for action in packet.actions:
 | 
				
			||||||
@@ -532,6 +534,9 @@ class Game:
 | 
				
			|||||||
        import os
 | 
					        import os
 | 
				
			||||||
        os._exit(1)
 | 
					        os._exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def handle_unload_chunk(self, packet):
 | 
				
			||||||
 | 
					        self.g.chunks.unload_chunk(packet.chunk_x, packet.chunk_z)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tick(self):
 | 
					    def tick(self):
 | 
				
			||||||
        if self.g.breaking:
 | 
					        if self.g.breaking:
 | 
				
			||||||
            self.animate()
 | 
					            self.animate()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ def get_packets(old_get_packets):
 | 
				
			|||||||
        mc_packets.add(packets.EntityTeleport)
 | 
					        mc_packets.add(packets.EntityTeleport)
 | 
				
			||||||
        mc_packets.add(packets.TradeListPacket)
 | 
					        mc_packets.add(packets.TradeListPacket)
 | 
				
			||||||
        mc_packets.add(packets.DisconnectPacket)
 | 
					        mc_packets.add(packets.DisconnectPacket)
 | 
				
			||||||
 | 
					        mc_packets.add(packets.UnloadChunkPacket)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mc_packets
 | 
					        return mc_packets
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,7 +70,6 @@ class ChunksManager:
 | 
				
			|||||||
                for item_id, locations in chunk.sub_index.items():
 | 
					                for item_id, locations in chunk.sub_index.items():
 | 
				
			||||||
                    if item_id not in self.index:
 | 
					                    if item_id not in self.index:
 | 
				
			||||||
                        self.index[item_id] = []
 | 
					                        self.index[item_id] = []
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for l in locations:
 | 
					                    for l in locations:
 | 
				
			||||||
                        coords = (dx + l%16, dy + l//256, dz + l%256//16)
 | 
					                        coords = (dx + l%16, dy + l//256, dz + l%256//16)
 | 
				
			||||||
                        self.index[item_id].append(coords)
 | 
					                        self.index[item_id].append(coords)
 | 
				
			||||||
@@ -122,28 +121,21 @@ class ChunksManager:
 | 
				
			|||||||
                self.index[block] = []
 | 
					                self.index[block] = []
 | 
				
			||||||
            self.index[block].append((x, y, z))
 | 
					            self.index[block].append((x, y, z))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_loaded(self, position, steps=1):
 | 
					    def check_loaded(self, chunk_distance):
 | 
				
			||||||
        x, y, z = utils.pint(position)
 | 
					        num = (chunk_distance * 2 + 1) ** 2
 | 
				
			||||||
        player_chunk = (x//16, 1, z//16)
 | 
					        num_subchunks = num * 16
 | 
				
			||||||
        for i in range(steps): # TODO: base off render_distance?
 | 
					        return len(self.chunks) >= num_subchunks
 | 
				
			||||||
            offset = utils.spiral(i)
 | 
					 | 
				
			||||||
            check = utils.padd(player_chunk, offset)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if check not in self.chunks:
 | 
					    def unload_chunk(self, x, z):
 | 
				
			||||||
                return False
 | 
					        for y in range(16):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
        return True
 | 
					                del self.chunks[(x, y, z)]
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
    def unload_chunks(self, position):
 | 
					                pass
 | 
				
			||||||
        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_all_chunks(self):
 | 
				
			||||||
 | 
					        self.chunks = {}
 | 
				
			||||||
 | 
					        self.index = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ChunkNotLoadedException(Exception):
 | 
					class ChunkNotLoadedException(Exception):
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,10 +31,10 @@ class ChunkDataPacket(Packet):
 | 
				
			|||||||
                self.biomes.append(VarInt.read(file_object))
 | 
					                self.biomes.append(VarInt.read(file_object))
 | 
				
			||||||
        size = VarInt.read(file_object)
 | 
					        size = VarInt.read(file_object)
 | 
				
			||||||
        self.data = file_object.read(size)
 | 
					        self.data = file_object.read(size)
 | 
				
			||||||
        size_entities = VarInt.read(file_object)
 | 
					        #size_entities = VarInt.read(file_object)
 | 
				
			||||||
        self.entities = []
 | 
					        #self.entities = []
 | 
				
			||||||
        for i in range(size_entities):
 | 
					        #for i in range(size_entities):
 | 
				
			||||||
            self.entities.append(Nbt.read(file_object))
 | 
					        #    self.entities.append(Nbt.read(file_object))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.decode_chunk_data()
 | 
					        self.decode_chunk_data()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,9 +49,9 @@ class ChunkDataPacket(Packet):
 | 
				
			|||||||
                Integer.send(self.biomes[i], packet_buffer)
 | 
					                Integer.send(self.biomes[i], packet_buffer)
 | 
				
			||||||
        VarInt.send(len(self.data), packet_buffer)
 | 
					        VarInt.send(len(self.data), packet_buffer)
 | 
				
			||||||
        packet_buffer.send(self.data)
 | 
					        packet_buffer.send(self.data)
 | 
				
			||||||
        VarInt.send(len(self.entities), packet_buffer)
 | 
					        #VarInt.send(len(self.entities), packet_buffer)
 | 
				
			||||||
        for e in self.entities:
 | 
					        #for e in self.entities:
 | 
				
			||||||
            Nbt.send(e, packet_buffer)
 | 
					        #    Nbt.send(e, packet_buffer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def decode_chunk_data(self):
 | 
					    def decode_chunk_data(self):
 | 
				
			||||||
        packet_data = PacketBuffer()
 | 
					        packet_data = PacketBuffer()
 | 
				
			||||||
@@ -64,9 +64,9 @@ class ChunkDataPacket(Packet):
 | 
				
			|||||||
            if self.bit_mask_y & (1 << i):
 | 
					            if self.bit_mask_y & (1 << i):
 | 
				
			||||||
                self.chunks[i].read(packet_data)
 | 
					                self.chunks[i].read(packet_data)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        for e in self.entities:
 | 
					        #for e in self.entities:
 | 
				
			||||||
            y = e['y']
 | 
					        #    y = e['y']
 | 
				
			||||||
            self.chunks[floor(y/16)].entities.append(e)
 | 
					        #    self.chunks[floor(y/16)].entities.append(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Chunk:
 | 
					class Chunk:
 | 
				
			||||||
    position = multi_attribute_alias(Vector, 'x', 'y', 'z')
 | 
					    position = multi_attribute_alias(Vector, 'x', 'y', 'z')
 | 
				
			||||||
@@ -458,3 +458,15 @@ class DisconnectPacket(Packet):
 | 
				
			|||||||
    definition = [
 | 
					    definition = [
 | 
				
			||||||
        {'reason': String},
 | 
					        {'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},
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user