Chunk loading and unloading works moving around

This commit is contained in:
Kyler 2024-04-20 23:44:18 -06:00
parent afeac68abc
commit c1c7fd1b43
1 changed files with 173 additions and 17 deletions

View File

@ -82,6 +82,122 @@ class Buffer_1_18_2(Buffer1_14):
raise NotImplementedError
class Player:
_conn: "YTDServerProtocol"
_name: str
_x: float
_y: float
_z: float
_yaw: float
_pitch: float
_chunks: set[tuple[int,int]]
_load_queue: list[tuple[int,int]]
_unload_queue: list[tuple[int,int]]
def __init__(
self,
connection: "YTDServerProtocol",
name: str,
x: float,
y: float,
z: float,
yaw: float,
pitch: float,
):
self._conn = connection
self._name = name
self._x = x
self._y = y
self._z = z
self._yaw = yaw
self._pitch = pitch
self._chunks = set()
self._load_queue = list()
self._unload_queue = list()
@property
def name(self) -> str:
return self._name
@property
def x(self) -> float:
return self._x
@property
def y(self) -> float:
return self._y
@property
def z(self) -> float:
return self._z
@property
def yaw(self) -> float:
return self._yaw
@yaw.setter
def yaw(self, value: float):
self._yaw = value
@property
def pitch(self) -> float:
return self._pitch
@pitch.setter
def pitch(self, value: float):
self._pitch = value
@property
def cx(self) -> int:
return int(self.x // 16)
@property
def cy(self) -> int:
return int(self.y // 16)
@property
def cz(self) -> int:
return int(self.z // 16)
def update_pos(self, x: float, y: float, z: float):
chunk_crossed = int(x // 16) != self.cx or int(z // 16) != self.cz
self._x = x
self._y = y
self._z = z
if chunk_crossed:
self.update_chunks()
def update_chunks(self):
print("Chunk Crossed")
vd = self._conn.view_distance
chunks: set[tuple[int,int]] = set()
for x in range(self.cx-vd, self.cx+vd+1):
for z in range(self.cz-vd, self.cz+vd+1):
chunks.add((x,z))
new_chunks = chunks.difference(self._chunks)
old_chunks = self._chunks.difference(chunks)
for i in new_chunks:
self.load_chunk(*i)
for i in old_chunks:
self.unload_chunk(*i)
self._conn.send_update_view_position(self.cx,self.cz)
def load_chunk(self, x: int, z: int):
print(f"enqueuing loading chunk {x}, {z}")
self._chunks.add((x,z))
self._load_queue.append((x,z))
# self._conn.send_chunk(x,z)
def unload_chunk(self, x: int, z: int):
print(f"enqueuing unloading chunk {x}, {z}")
try: self._chunks.remove((x,z))
except KeyError: pass
self._unload_queue.append((x,z))
# self._conn.send_unload_chunk(x,z)
class YTDServerProtocol(ServerProtocol):
def player_joined(self):
@ -89,6 +205,17 @@ class YTDServerProtocol(ServerProtocol):
# in-game, and does some logging.
ServerProtocol.player_joined(self)
self.buff_type = Buffer_1_18_2
self.view_distance = 2
self.player = Player(
self,
self.display_name, # type: ignore
0,
325,
0,
0,
0,
)
# Send join game packet
self.send_join_game()
@ -97,17 +224,18 @@ class YTDServerProtocol(ServerProtocol):
self.send_packet(
"player_position_and_look",
self.buff_type.pack("dddff?",
0, # x
325, # y Must be >= build height to pass the "Loading Terrain" screen on 1.18.2
0, # z
0, # yaw
0, # pitch
0b00000), # flags
self.buff_type.pack_varint(0), # teleport id
self.buff_type.pack("?", True)) # Leave vehicle
self.player.x,
self.player.y,
self.player.z,
self.player.yaw,
self.player.pitch,
0b00000),
self.buff_type.pack_varint(0),
self.buff_type.pack("?", True))
# Start sending "Keep Alive" packets
self.ticker.add_loop(20, self.update_keep_alive)
self.ticker.add_loop(1, self.manage_queue)
# Announce player join to other players
self.factory.broadcast_player_join(self)
@ -116,10 +244,14 @@ class YTDServerProtocol(ServerProtocol):
self.factory.send_player_list_add(self, self.factory.players)
self.send_update_view_position(0,0)
self.send_chunk(0,0)
self.send_chunk(-1,0)
self.send_chunk(0,-1)
self.send_chunk(-1,-1)
self.player.load_chunk(0,0)
self.player.load_chunk(-1,0)
self.player.load_chunk(0,-1)
self.player.load_chunk(-1,-1)
# self.send_chunk(0,0)
# self.send_chunk(-1,0)
# self.send_chunk(0,-1)
# self.send_chunk(-1,-1)
# self.send_chunk(1,0)
# self.send_chunk(0,1)
# self.send_chunk(1,1)
@ -130,7 +262,7 @@ class YTDServerProtocol(ServerProtocol):
entity_id = 0
max_players = 0
hashed_seed = 42
view_distance = 2
view_distance = self.view_distance
simulation_distance = 2
game_mode = 3
prev_game_mode = 3
@ -167,6 +299,22 @@ class YTDServerProtocol(ServerProtocol):
# Send "Join Game" packet
self.send_packet("join_game", *join_game)
def manage_queue(self):
if self.player._load_queue:
x,z = self.player._load_queue.pop(0)
while (x,z) in self.player._load_queue:
self.player._load_queue.remove((x,z))
print(f"dequeuing loading chunk {x}, {z}")
self.send_chunk(x,z)
elif self.player._unload_queue:
x,z = self.player._unload_queue.pop(0)
while (x,z) in self.player._unload_queue:
self.player._unload_queue.remove((x,z))
print(f"dequeuing unloading chunk {x}, {z}")
self.send_unload_chunk(x,z)
# else:
# print("queues empty")
def player_left(self):
ServerProtocol.player_left(self)
@ -194,14 +342,22 @@ class YTDServerProtocol(ServerProtocol):
self.buff_type.pack_varint(z),
)
# def send_chunk(self, x, z, full, heightmap, sections, biomes):
def send_chunk(self, x, z):
sections, heightmap = self.factory.generate(x,z)
sections_data = self.buff_type.pack_chunk(sections)
def packet_player_position(self, buff: Buffer_1_18_2):
self.player.update_pos(*buff.unpack('ddd'))
buff.discard()
def send_unload_chunk(self, x, z):
self.send_packet(
'unload_chunk',
self.buff_type.pack('ii', x, z),
)
# def send_chunk(self, x, z, full, heightmap, sections, biomes):
def send_chunk(self, x, z):
sections, heightmap = self.factory.generate(x,z)
sections_data = self.buff_type.pack_chunk(sections)
self.send_unload_chunk(x,z)
self.send_packet(
'chunk_data',
self.buff_type.pack('ii', x, z),