From b40fee3c3c6094e737e1b01bb46382e77e64b43d Mon Sep 17 00:00:00 2001 From: Kodi Craft Date: Fri, 4 Oct 2024 11:36:08 +0200 Subject: [PATCH] Fix bugs in sending paletted chunks --- apps/amethyst/lib/apps/connection_handler.ex | 27 ++++++++++-------- apps/amethyst/lib/states/play.ex | 3 +- apps/example_game/lib/example/game.ex | 29 ++++++++++---------- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/apps/amethyst/lib/apps/connection_handler.ex b/apps/amethyst/lib/apps/connection_handler.ex index 70ad8bf..7c6625b 100644 --- a/apps/amethyst/lib/apps/connection_handler.ex +++ b/apps/amethyst/lib/apps/connection_handler.ex @@ -61,13 +61,12 @@ defmodule Amethyst.ConnectionHandler do 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)) + prev_cp = if prev_position == nil do nil else chunk_pos(elem(prev_position, 0), elem(prev_position, 2)) end + cp = chunk_pos(elem(position, 0), elem(position, 2)) 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 @@ -85,6 +84,7 @@ defmodule Amethyst.ConnectionHandler do 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) + Logger.debug("Sending #{MapSet.size(new_chunks)} chunks...") # We can process all chunks in parallel me = self() ts = state |> Map.get(:game) |> Map.get(:refs) |> Map.get(:task_supervisor) @@ -110,13 +110,13 @@ defmodule Amethyst.ConnectionHandler do end defp chunk_pos(x, z) do - {div(floor(x), 16), div(floor(z), 16)} + {floor(round(x) / 16.0), floor(round(z) / 16.0)} end + # x, z here is chunk position 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 -> + (x - view_distance - 3 .. x + view_distance + 3) |> Enum.flat_map(fn ix -> + (z - view_distance - 3 .. z + view_distance + 3) |> Enum.map(fn iz -> {ix, iz} end) end) @@ -154,15 +154,18 @@ defmodule Amethyst.ConnectionHandler do bpe = max(min_bpe, 4) palette = MapSet.to_list(unique_blocks) |> Enum.with_index() |> - Map.new(fn {i, v} -> {v, i} end) + Map.new(fn {i, v} -> {i, v} end) + Logger.debug("Using palette #{inspect(palette)}") paletted_blocks = blocks |> Enum.map(&(Map.get(palette, &1))) + Logger.debug("Paletted blocks: #{inspect(paletted_blocks)}") paletted_data = long_aligned_bit_string_reduce(paletted_blocks, bpe) + Logger.debug("Paletted data: #{inspect(paletted_data)}") Write.ubyte(bpe) <> Write.varint(map_size(palette)) <> - Enum.reduce(0..(map_size(palette)-1), "", fn i, acc -> - acc <> Write.varint(Map.get(palette, i)) + Enum.reduce(palette, "", fn {_k, v}, acc -> + acc <> Write.varint(v) end) <> Write.varint(floor(bit_size(paletted_data) / 64)) <> paletted_data @@ -197,9 +200,9 @@ defmodule Amethyst.ConnectionHandler do defp long_aligned_bit_string_reduce(values, bpe) do values |> Enum.reduce(<<>>, fn value, acc -> - next = <> + next = <> # man i hope they dont suddenly change the size of a long - if rem(bit_size(next), 64) + bpe < 64 do + if rem(bit_size(next), 64) + bpe > 64 do # gotta pad it <> else diff --git a/apps/amethyst/lib/states/play.ex b/apps/amethyst/lib/states/play.ex index 69c4855..69d70d7 100644 --- a/apps/amethyst/lib/states/play.ex +++ b/apps/amethyst/lib/states/play.ex @@ -208,7 +208,7 @@ defmodule Amethyst.ConnectionState.Play do def handle(%{packet_type: :set_player_on_ground, on_ground: _}, 767, _state) do :ok # Again, don't trust the client for something we can compute end - def handle(%{packet_type: :player_command, eid: _eid, action_id: aid, jump_boost: _horse_jump}, 767, state) do + def handle(%{packet_type: :player_command, eid: _eid, action_id: aid, jump_boost: _horse_jump}, 767, _state) do # TODO: Actually handle these events case aid do 0 -> # Start sneaking @@ -243,7 +243,6 @@ defmodule Amethyst.ConnectionState.Play do def keepalive_loop(player) do Process.link(player) # Is it fine to do this on loop? <> = :rand.bytes(4) - Logger.debug("Sending keepalive...") send(player, {:send_packet, %{packet_type: :keep_alive, id: id}}) receive do {:respond, ^id} -> diff --git a/apps/example_game/lib/example/game.ex b/apps/example_game/lib/example/game.ex index ce7beab..a0a813b 100644 --- a/apps/example_game/lib/example/game.ex +++ b/apps/example_game/lib/example/game.ex @@ -12,19 +12,20 @@ defmodule Example.Game do def login(from, cfg, refs) do Logger.info("Player logged in from #{inspect(from)}: #{inspect(cfg)}") Logger.info("The refs for this game are #{inspect(refs)}") - {:accept, {0.0, 10.0, 0.0}, {0.0, 0.0}} + {:accept, {0.0, 270.0, 0.0}, {0.0, 0.0}} end @impl true @spec player_position(any(), {any(), any(), any()}, any()) :: :ok def player_position(from, {x, y, z}, _refs) do - Logger.info("Player at #{inspect(from)} moved to #{x}, #{y}, #{z}") + # Logger.info("Player at #{inspect(from)} moved to #{x}, #{y}, #{z}") + send(from, {:set_position, {x, y, z}}) :ok end @impl true - def player_rotation(from, {yaw, pitch}, _refs) do - Logger.info("Player at #{inspect(from)} rotated to #{yaw}, #{pitch}") + def player_rotation(_from, {_yaw, _pitch}, _refs) do + # Logger.info("Player at #{inspect(from)} rotated to #{yaw}, #{pitch}") :ok end @@ -40,18 +41,18 @@ defmodule Example.Game do end @impl true - def chunk(_from, {_x, _z}, _state_refs) do - # Logger.info("Player at #{inspect(from)} wants to know chunk #{x}, #{z}") + def chunk(_from, {_cx, _cz}, _state_refs) do + # Logger.info("Player at #{inspect(from)} wants to know chunk #{cx}, #{cz}") (0..255) |> Enum.map(fn y -> - if y < 5 do - (0..15) |> Enum.map(fn _z -> - (0..15) |> Enum.map(fn _x -> 1 end) + (0..15) |> Enum.map(fn z -> + (0..15) |> Enum.map(fn x -> + if y <= x + z do + 3 + else + 0 + end end) - else - (0..15) |> Enum.map(fn _z -> - (0..15) |> Enum.map(fn _x -> 1 end) - end) - end + end) end) end end