Handle loading / unloading chunks better

This commit is contained in:
Tanner Collin 2021-05-07 00:14:25 +00:00
parent 5184d4a173
commit e5fd062a4a
6 changed files with 48 additions and 38 deletions

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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):

View File

@ -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},
]