From 453daa817b37ac9b32f64efb41c12350207306fb Mon Sep 17 00:00:00 2001 From: Kodi Craft Date: Tue, 1 Oct 2024 10:51:08 +0200 Subject: [PATCH] Implement part of chunk sending --- apps/amethyst/lib/apps/connection_handler.ex | 50 ++++++++++++++++++++ apps/amethyst/lib/states/configuration.ex | 5 +- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/apps/amethyst/lib/apps/connection_handler.ex b/apps/amethyst/lib/apps/connection_handler.ex index ac43cbe..d36a090 100644 --- a/apps/amethyst/lib/apps/connection_handler.ex +++ b/apps/amethyst/lib/apps/connection_handler.ex @@ -60,6 +60,39 @@ defmodule Amethyst.ConnectionHandler do {:set_version, newversion} -> Logger.debug("Switching to version #{newversion} from #{version}") loop(socket, connstate, newversion, state) + {:set_position, position} -> + Logger.debug("Updating client position to #{inspect(position)}") + prev_position = Map.get(state, :position) + state = Map.put(state, :position, position) + # If there was no prev position, we consider that we + # definitely moved + prev_cp = if prev_position == nil do nil else chunk_pos(elem(prev_position, 0), elem(prev_position, 1)) end + cp = chunk_pos(elem(position, 0), elem(position, 1)) + if prev_cp != cp do + Logger.debug("Client entered new chunk #{inspect(cp)}") + # We changed chunk borders, update center chunk and begin sending new chunks + send(self(), {:send_packet, %{ + packet_type: :set_center_chunk, + chunk_x: elem(cp, 0), + chunk_z: elem(cp, 1) + }}) + # Figure out which new chunks are visible + prev_chunks = + if prev_cp == nil do + MapSet.new([]) + else + MapSet.new(visible_chunks_from(elem(prev_cp, 0), elem(prev_cp, 1), Map.get(state, :view_distance, 16))) + end + chunks = MapSet.new(visible_chunks_from(elem(cp, 0), elem(cp, 1), Map.get(state, :view_distance, 16))) + new_chunks = MapSet.difference(chunks, prev_chunks) + # Process these chunks, we can process all chunks in parallel + Task.Supervisor.async_stream(state |> Map.get(:game) |> Map.get(:refs) |> Map.get(:task_supervisor), + new_chunks, + fn chunk -> process_chunk(chunk, state) end, + [ordered: false] + ) |> Stream.run() + end + loop(socket, connstate, version, state) {:send_packet, packet} -> Logger.debug("Sending packet #{inspect(packet)}") send_packet(socket, connstate, packet, version) @@ -73,6 +106,23 @@ defmodule Amethyst.ConnectionHandler do end end + defp chunk_pos(x, z) do + {div(floor(x), 16), div(floor(z), 16)} + end + + defp visible_chunks_from(x, z, view_distance) do + {cx, cz} = chunk_pos(x, z) + (cx - view_distance - 3 .. cx + view_distance + 3) |> Enum.flat_map(fn ix -> + (cz - view_distance - 3 .. cz + view_distance + 3) |> Enum.map(fn iz -> + {ix, iz} + end) + end) + end + + defp process_chunk(_chunk, _state) do + # TODO: Actually ask the game for the desired chunk then send the packets. + end + defp handle_packet(id, data, connstate, version, state) do try do packet = connstate.deserialize(id, version, data) diff --git a/apps/amethyst/lib/states/configuration.ex b/apps/amethyst/lib/states/configuration.ex index c4e99a9..7426b65 100644 --- a/apps/amethyst/lib/states/configuration.ex +++ b/apps/amethyst/lib/states/configuration.ex @@ -305,9 +305,10 @@ defmodule Amethyst.ConnectionState.Configuration do }}) send(self(), {:send_packet, Amethyst.ConnectionState.Play.ge_start_waiting_for_level_chunks(767)}) send(self(), {:send_packet, %{packet_type: :set_center_chunk, - chunk_x: div(x, 16), - chunk_y: div(z, 16) + chunk_x: div(floor(x), 16), + chunk_z: div(floor(z), 16) }}) + send(self(), {:set_position, {x, y, z}}) state end end