Attempt implementing light
All checks were successful
Build & Test / nix-build (push) Successful in 1m49s
All checks were successful
Build & Test / nix-build (push) Successful in 1m49s
This commit is contained in:
parent
5743ae55e0
commit
b44784e9ef
@ -154,39 +154,42 @@ defmodule Amethyst.ConnectionHandler do
|
||||
|
||||
data = Enum.chunk_every(chunk_array, 16, 16, 0) # 0 -> air
|
||||
|> Enum.reduce("", fn chunk_section, acc ->
|
||||
blocks = chunk_section |> List.flatten()
|
||||
block_count = blocks |> Enum.filter(&(&1 != 0)) |> length
|
||||
blocks_and_lights = chunk_section |> List.flatten()
|
||||
block_count = blocks_and_lights |> Enum.filter(fn {bs, _, _} -> bs != 0 end) |> length
|
||||
|
||||
# Put together the palette
|
||||
unique_blocks = MapSet.new(blocks)
|
||||
unique_blocks = MapSet.new(blocks_and_lights |> Enum.map(fn {bs, _, _} -> bs end))
|
||||
min_bpe = MapSet.size(unique_blocks) |> :math.log2() |> ceil()
|
||||
|
||||
paletted_container_data = case min_bpe do
|
||||
0 ->
|
||||
# SINGLE VALUED
|
||||
Write.ubyte(0) <>
|
||||
Write.varint(MapSet.to_list(unique_blocks) |> List.first()) <>
|
||||
Write.varint(0) # No data, empty pallette
|
||||
|
||||
min_bpe when min_bpe in 1..8 ->
|
||||
# INDIRECT
|
||||
# Minimum bpe accepted by minecraft is 4
|
||||
bpe = max(min_bpe, 4)
|
||||
palette = MapSet.to_list(unique_blocks) |>
|
||||
Enum.with_index() |>
|
||||
Map.new(fn {i, v} -> {i, v} end)
|
||||
paletted_blocks = blocks |>
|
||||
Enum.map(&(Map.get(palette, &1)))
|
||||
paletted_data = long_aligned_bit_string_reduce(paletted_blocks, bpe)
|
||||
|
||||
Map.new(fn {v, i} -> {v, i} end)
|
||||
paletted_blocks = blocks_and_lights |>
|
||||
Enum.map(fn {bs, _, _} -> Map.get(palette, bs) end)
|
||||
paletted_data = long_aligned_bit_string_reduce(paletted_blocks, bpe,
|
||||
fn bs -> <<bs::signed-integer-big-size(bpe)>> end)
|
||||
Write.ubyte(bpe) <>
|
||||
Write.varint(map_size(palette)) <>
|
||||
Enum.reduce(palette, "", fn {_k, v}, acc ->
|
||||
acc <> Write.varint(v)
|
||||
end) <>
|
||||
(Enum.sort(palette, fn {_k1, v1}, {_k2, v2} -> v1 < v2 end) |>
|
||||
Enum.reduce("", fn {k, _v}, acc -> acc <> Write.varint(k) end)) <>
|
||||
Write.varint(floor(bit_size(paletted_data) / 64)) <>
|
||||
paletted_data
|
||||
|
||||
_ ->
|
||||
# DIRECT
|
||||
data = long_aligned_bit_string_reduce(blocks, 15)
|
||||
data = long_aligned_bit_string_reduce(blocks_and_lights, 15,
|
||||
fn {bs, _sl, _bl} -> <<bs::signed-integer-big-size(15)>> end)
|
||||
Write.ubyte(15) <>
|
||||
Write.varint(floor(bit_size(data) / 64)) <>
|
||||
data
|
||||
@ -196,26 +199,48 @@ defmodule Amethyst.ConnectionHandler do
|
||||
<<0::8, 0::8, 0::8>> # TODO: This should be biome data
|
||||
end)
|
||||
|
||||
sky_light_sections = Enum.chunk_every(chunk_array, 16, 16, 0)
|
||||
|> Enum.map(fn chunk_section ->
|
||||
chunk_section |> List.flatten() |> Enum.map(fn {_bs, sl, _bl} -> sl end)
|
||||
end)
|
||||
non_empty_sky_light_sections = sky_light_sections |> Enum.filter(fn section -> !Enum.all?(section, &(&1 == 0)) end)
|
||||
has_sky_light = [false] ++ (sky_light_sections |> Enum.map(fn section -> !Enum.all?(section, &(&1 == 0)) end)) ++ [false]
|
||||
empty_sky_light = has_sky_light |> Enum.map(¬/1)
|
||||
sky_light_array = non_empty_sky_light_sections |> Enum.map(&(Enum.reduce(&1, <<>>, fn light, acc ->
|
||||
<<acc::bitstring, light::size(4)>>
|
||||
end)))
|
||||
|
||||
block_light_sections = Enum.chunk_every(chunk_array, 16, 16, 0)
|
||||
|> Enum.map(fn chunk_section ->
|
||||
chunk_section |> List.flatten() |> Enum.map(fn {_bs, _sl, bl} -> bl end)
|
||||
end)
|
||||
non_empty_block_light_sections = block_light_sections |> Enum.filter(fn section -> !Enum.all?(section, &(&1 == 0)) end)
|
||||
has_block_light = [false] ++ (block_light_sections |> Enum.map(fn section -> !Enum.all?(section, &(&1 == 0)) end)) ++ [false]
|
||||
empty_block_light = has_block_light |> Enum.map(¬/1)
|
||||
block_light_array = non_empty_block_light_sections |> Enum.map(&(Enum.reduce(&1, <<>>, fn light, acc ->
|
||||
<<acc::bitstring, light::size(4)>>
|
||||
end)))
|
||||
|
||||
send(to, {:send_packet, %{
|
||||
packet_type: :chunk_data_and_update_light,
|
||||
chunk_x: cx, chunk_z: cz,
|
||||
heightmaps: heightmaps,
|
||||
data: data,
|
||||
block_entities: [],
|
||||
# TODO: Light
|
||||
sky_light_mask: Write.varint(0),
|
||||
block_light_mask: Write.varint(0),
|
||||
empty_sky_light_mask: Write.varint(0),
|
||||
empty_block_light_mask: Write.varint(0),
|
||||
sky_light_arrays: [],
|
||||
block_light_arrays: []
|
||||
sky_light_mask: has_sky_light,
|
||||
block_light_mask: has_block_light,
|
||||
empty_sky_light_mask: empty_sky_light,
|
||||
empty_block_light_mask: empty_block_light,
|
||||
sky_light_arrays: sky_light_array |> Enum.map(&(%{sky_light_array: &1})),
|
||||
block_light_arrays: block_light_array |> Enum.map(&(%{block_light_array: &1}))
|
||||
}})
|
||||
:ok
|
||||
end
|
||||
|
||||
defp long_aligned_bit_string_reduce(values, bpe) do
|
||||
defp long_aligned_bit_string_reduce(values, bpe, func) do
|
||||
values |> Enum.reduce(<<>>, fn value, acc ->
|
||||
next = <<acc::bitstring, value::big-size(bpe)>>
|
||||
ret = func.(value)
|
||||
next = <<acc::bitstring, ret::bitstring-size(bpe)>>
|
||||
# man i hope they dont suddenly change the size of a long
|
||||
if rem(bit_size(next), 64) + bpe > 64 do
|
||||
# gotta pad it
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
defmodule Amethyst.Minecraft.Write do
|
||||
import Bitwise
|
||||
require Logger
|
||||
|
||||
@moduledoc """
|
||||
This module contains functions for writing Minecraft data.
|
||||
@ -139,6 +140,18 @@ defmodule Amethyst.Minecraft.Write do
|
||||
def nbt(value) do
|
||||
Amethyst.NBT.Write.write_net(value)
|
||||
end
|
||||
|
||||
def bitset(list) do
|
||||
Logger.debug("Writing bitset #{inspect(list)}")
|
||||
unaligned = Enum.reduce(list, <<>>, &(if &1 do <<&2::bitstring, 1::1>> else <<&2::bitstring, 0::1>> end))
|
||||
aligned = if rem(bit_size(unaligned), 64) == 0 do
|
||||
unaligned
|
||||
else
|
||||
<<unaligned::bitstring, 0::size(64 - rem(bit_size(unaligned), 64))>>
|
||||
end
|
||||
Logger.debug("Writing as #{inspect(aligned)}")
|
||||
varint(div(byte_size(aligned), 8)) <> aligned
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Amethyst.Minecraft.Read do
|
||||
|
@ -92,7 +92,7 @@ defmodule Amethyst.Game do
|
||||
|
||||
For now, this data must be formatted as a 3D list, indexed as [y][z][x].
|
||||
"""
|
||||
@callback chunk(from :: pid(), {x :: integer(), z :: integer()}, state_refs :: map()) :: [[[pos_integer()]]]
|
||||
@callback chunk(from :: pid(), {x :: integer(), z :: integer()}, state_refs :: map()) :: [[[{block_state :: pos_integer(), sky_light :: 0..15, block_light :: 0..15}]]]
|
||||
def chunk(%{:mod => mod, :refs => refs}, pos) do
|
||||
mod.chunk(self(), pos, refs)
|
||||
end
|
||||
|
@ -154,6 +154,7 @@ defmodule Amethyst.ConnectionState.Macros do
|
||||
def type_matches(value, {:optional, _type}) when is_nil(value), do: true
|
||||
def type_matches(value, {:optional, type}), do: type_matches(value, type)
|
||||
def type_matches(value, {:array, signature}) when is_list(value), do: Enum.all?(value, fn item -> check_type(item, signature) end)
|
||||
def type_matches(value, :bitset) when is_list(value), do: Enum.all?(value, fn item -> is_boolean(item) end)
|
||||
def type_matches(value, {:compound, signature}) when is_map(value), do: check_type(value, signature)
|
||||
def type_matches(_, _) do
|
||||
false
|
||||
|
@ -36,10 +36,10 @@ defmodule Amethyst.ConnectionState.Play do
|
||||
type: :varint,
|
||||
data: :nbt
|
||||
]},
|
||||
sky_light_mask: :raw,
|
||||
block_light_mask: :raw,
|
||||
empty_sky_light_mask: :raw,
|
||||
empty_block_light_mask: :raw,
|
||||
sky_light_mask: :bitset,
|
||||
block_light_mask: :bitset,
|
||||
empty_sky_light_mask: :bitset,
|
||||
empty_block_light_mask: :bitset,
|
||||
sky_light_arrays: {:array, [
|
||||
sky_light_array: :byte_array
|
||||
]},
|
||||
|
@ -46,13 +46,13 @@ defmodule Example.Game do
|
||||
(0..255) |> Enum.map(fn y ->
|
||||
(0..15) |> Enum.map(fn z ->
|
||||
(0..15) |> Enum.map(fn x ->
|
||||
gx = cx*16 + x
|
||||
gz = cz*16 + z
|
||||
gx = cx * 16 + x
|
||||
gz = cz * 16 + z
|
||||
gy = y
|
||||
if rem(gx, 4) == 0 && rem(gy, 4) == 0 && rem(gz, 4) == 0 do
|
||||
1
|
||||
{abs(rem(div(gx + gy + gz, 4), 1000)), 15, 0}
|
||||
else
|
||||
0
|
||||
{0, 15, 0}
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user