Fix bugs in sending paletted chunks
This commit is contained in:
parent
288ead3e9b
commit
b40fee3c3c
@ -61,13 +61,12 @@ defmodule Amethyst.ConnectionHandler do
|
|||||||
Logger.debug("Switching to version #{newversion} from #{version}")
|
Logger.debug("Switching to version #{newversion} from #{version}")
|
||||||
loop(socket, connstate, newversion, state)
|
loop(socket, connstate, newversion, state)
|
||||||
{:set_position, position} ->
|
{:set_position, position} ->
|
||||||
Logger.debug("Updating client position to #{inspect(position)}")
|
|
||||||
prev_position = Map.get(state, :position)
|
prev_position = Map.get(state, :position)
|
||||||
state = Map.put(state, :position, position)
|
state = Map.put(state, :position, position)
|
||||||
# If there was no prev position, we consider that we
|
# If there was no prev position, we consider that we
|
||||||
# definitely moved
|
# definitely moved
|
||||||
prev_cp = if prev_position == nil do nil else chunk_pos(elem(prev_position, 0), elem(prev_position, 1)) end
|
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, 1))
|
cp = chunk_pos(elem(position, 0), elem(position, 2))
|
||||||
if prev_cp != cp do
|
if prev_cp != cp do
|
||||||
Logger.debug("Client entered new chunk #{inspect(cp)}")
|
Logger.debug("Client entered new chunk #{inspect(cp)}")
|
||||||
# We changed chunk borders, update center chunk and begin sending new chunks
|
# We changed chunk borders, update center chunk and begin sending new chunks
|
||||||
@ -85,6 +84,7 @@ defmodule Amethyst.ConnectionHandler do
|
|||||||
end
|
end
|
||||||
chunks = MapSet.new(visible_chunks_from(elem(cp, 0), elem(cp, 1), Map.get(state, :view_distance, 16)))
|
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)
|
new_chunks = MapSet.difference(chunks, prev_chunks)
|
||||||
|
Logger.debug("Sending #{MapSet.size(new_chunks)} chunks...")
|
||||||
# We can process all chunks in parallel
|
# We can process all chunks in parallel
|
||||||
me = self()
|
me = self()
|
||||||
ts = state |> Map.get(:game) |> Map.get(:refs) |> Map.get(:task_supervisor)
|
ts = state |> Map.get(:game) |> Map.get(:refs) |> Map.get(:task_supervisor)
|
||||||
@ -110,13 +110,13 @@ defmodule Amethyst.ConnectionHandler do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp chunk_pos(x, z) do
|
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
|
end
|
||||||
|
|
||||||
|
# x, z here is chunk position
|
||||||
defp visible_chunks_from(x, z, view_distance) do
|
defp visible_chunks_from(x, z, view_distance) do
|
||||||
{cx, cz} = chunk_pos(x, z)
|
(x - view_distance - 3 .. x + view_distance + 3) |> Enum.flat_map(fn ix ->
|
||||||
(cx - view_distance - 3 .. cx + view_distance + 3) |> Enum.flat_map(fn ix ->
|
(z - view_distance - 3 .. z + view_distance + 3) |> Enum.map(fn iz ->
|
||||||
(cz - view_distance - 3 .. cz + view_distance + 3) |> Enum.map(fn iz ->
|
|
||||||
{ix, iz}
|
{ix, iz}
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
@ -154,15 +154,18 @@ defmodule Amethyst.ConnectionHandler do
|
|||||||
bpe = max(min_bpe, 4)
|
bpe = max(min_bpe, 4)
|
||||||
palette = MapSet.to_list(unique_blocks) |>
|
palette = MapSet.to_list(unique_blocks) |>
|
||||||
Enum.with_index() |>
|
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 |>
|
paletted_blocks = blocks |>
|
||||||
Enum.map(&(Map.get(palette, &1)))
|
Enum.map(&(Map.get(palette, &1)))
|
||||||
|
Logger.debug("Paletted blocks: #{inspect(paletted_blocks)}")
|
||||||
paletted_data = long_aligned_bit_string_reduce(paletted_blocks, bpe)
|
paletted_data = long_aligned_bit_string_reduce(paletted_blocks, bpe)
|
||||||
|
Logger.debug("Paletted data: #{inspect(paletted_data)}")
|
||||||
|
|
||||||
Write.ubyte(bpe) <>
|
Write.ubyte(bpe) <>
|
||||||
Write.varint(map_size(palette)) <>
|
Write.varint(map_size(palette)) <>
|
||||||
Enum.reduce(0..(map_size(palette)-1), "", fn i, acc ->
|
Enum.reduce(palette, "", fn {_k, v}, acc ->
|
||||||
acc <> Write.varint(Map.get(palette, i))
|
acc <> Write.varint(v)
|
||||||
end) <>
|
end) <>
|
||||||
Write.varint(floor(bit_size(paletted_data) / 64)) <>
|
Write.varint(floor(bit_size(paletted_data) / 64)) <>
|
||||||
paletted_data
|
paletted_data
|
||||||
@ -197,9 +200,9 @@ defmodule Amethyst.ConnectionHandler do
|
|||||||
|
|
||||||
defp long_aligned_bit_string_reduce(values, bpe) do
|
defp long_aligned_bit_string_reduce(values, bpe) do
|
||||||
values |> Enum.reduce(<<>>, fn value, acc ->
|
values |> Enum.reduce(<<>>, fn value, acc ->
|
||||||
next = <<acc::bitstring, value::size(bpe)-big>>
|
next = <<acc::bitstring, value::big-size(bpe)>>
|
||||||
# man i hope they dont suddenly change the size of a long
|
# 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
|
# gotta pad it
|
||||||
<<next::bitstring, 0::big-size(64 - rem(bit_size(next), 64))>>
|
<<next::bitstring, 0::big-size(64 - rem(bit_size(next), 64))>>
|
||||||
else
|
else
|
||||||
|
@ -208,7 +208,7 @@ defmodule Amethyst.ConnectionState.Play do
|
|||||||
def handle(%{packet_type: :set_player_on_ground, on_ground: _}, 767, _state) 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
|
:ok # Again, don't trust the client for something we can compute
|
||||||
end
|
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
|
# TODO: Actually handle these events
|
||||||
case aid do
|
case aid do
|
||||||
0 -> # Start sneaking
|
0 -> # Start sneaking
|
||||||
@ -243,7 +243,6 @@ defmodule Amethyst.ConnectionState.Play do
|
|||||||
def keepalive_loop(player) do
|
def keepalive_loop(player) do
|
||||||
Process.link(player) # Is it fine to do this on loop?
|
Process.link(player) # Is it fine to do this on loop?
|
||||||
<<id::32>> = :rand.bytes(4)
|
<<id::32>> = :rand.bytes(4)
|
||||||
Logger.debug("Sending keepalive...")
|
|
||||||
send(player, {:send_packet, %{packet_type: :keep_alive, id: id}})
|
send(player, {:send_packet, %{packet_type: :keep_alive, id: id}})
|
||||||
receive do
|
receive do
|
||||||
{:respond, ^id} ->
|
{:respond, ^id} ->
|
||||||
|
@ -12,19 +12,20 @@ defmodule Example.Game do
|
|||||||
def login(from, cfg, refs) do
|
def login(from, cfg, refs) do
|
||||||
Logger.info("Player logged in from #{inspect(from)}: #{inspect(cfg)}")
|
Logger.info("Player logged in from #{inspect(from)}: #{inspect(cfg)}")
|
||||||
Logger.info("The refs for this game are #{inspect(refs)}")
|
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
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
@spec player_position(any(), {any(), any(), any()}, any()) :: :ok
|
@spec player_position(any(), {any(), any(), any()}, any()) :: :ok
|
||||||
def player_position(from, {x, y, z}, _refs) do
|
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
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def player_rotation(from, {yaw, pitch}, _refs) do
|
def player_rotation(_from, {_yaw, _pitch}, _refs) do
|
||||||
Logger.info("Player at #{inspect(from)} rotated to #{yaw}, #{pitch}")
|
# Logger.info("Player at #{inspect(from)} rotated to #{yaw}, #{pitch}")
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -40,18 +41,18 @@ defmodule Example.Game do
|
|||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def chunk(_from, {_x, _z}, _state_refs) do
|
def chunk(_from, {_cx, _cz}, _state_refs) do
|
||||||
# Logger.info("Player at #{inspect(from)} wants to know chunk #{x}, #{z}")
|
# Logger.info("Player at #{inspect(from)} wants to know chunk #{cx}, #{cz}")
|
||||||
(0..255) |> Enum.map(fn y ->
|
(0..255) |> Enum.map(fn y ->
|
||||||
if y < 5 do
|
(0..15) |> Enum.map(fn z ->
|
||||||
(0..15) |> Enum.map(fn _z ->
|
(0..15) |> Enum.map(fn x ->
|
||||||
(0..15) |> Enum.map(fn _x -> 1 end)
|
if y <= x + z do
|
||||||
|
3
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
else
|
end)
|
||||||
(0..15) |> Enum.map(fn _z ->
|
|
||||||
(0..15) |> Enum.map(fn _x -> 1 end)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user