Handle loading / unloading chunks better
This commit is contained in:
parent
5184d4a173
commit
e5fd062a4a
|
@ -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},
|
||||||
|
]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user