Implement packet type checking and get back up to speed
This commit is contained in:
parent
4beb083dd6
commit
5063e8af12
@ -87,7 +87,7 @@ alias ElixirSense.Log
|
|||||||
if is_map(newstate) do
|
if is_map(newstate) do
|
||||||
newstate
|
newstate
|
||||||
else
|
else
|
||||||
Logger.warning("State change to #{newstate} is not a map! Did you forget to return :ok?")
|
Logger.warning("State change to #{inspect(newstate)} is not a map! Did you forget to return :ok?")
|
||||||
state
|
state
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -100,9 +100,15 @@ alias ElixirSense.Log
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp send_packet(socket, connstate, packet, version) do
|
defp send_packet(socket, connstate, packet, version) do
|
||||||
data = connstate.serialize(packet, version)
|
try do
|
||||||
length = byte_size(data) |> Amethyst.Minecraft.Write.varint()
|
data = connstate.serialize(packet, version)
|
||||||
:gen_tcp.send(socket, length <> data)
|
length = byte_size(data) |> Amethyst.Minecraft.Write.varint()
|
||||||
|
:gen_tcp.send(socket, length <> data)
|
||||||
|
rescue
|
||||||
|
e ->
|
||||||
|
Logger.error("Error sending packet #{inspect(packet)} in state #{connstate}: #{Exception.format(:error, e, __STACKTRACE__)}")
|
||||||
|
send(self(), {:disconnect, "§cError sending packet #{inspect(packet)}:\n#{Exception.format(:error, e, __STACKTRACE__)}"})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp disconnect(socket, reason, connstate, version) do
|
defp disconnect(socket, reason, connstate, version) do
|
||||||
|
@ -27,6 +27,20 @@ defmodule Amethyst.NBT.Write do
|
|||||||
<<type_id(type)::size(8), payload(type, value)::binary>>
|
<<type_id(type)::size(8), payload(type, value)::binary>>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_type({:byte, value}) when is_integer(value) and value in -128..127, do: true
|
||||||
|
def check_type({:short, value}) when is_integer(value) and value in -32_768..32_767, do: true
|
||||||
|
def check_type({:int, value}) when is_integer(value) and value in -2_147_483_648..2_147_483_647, do: true
|
||||||
|
def check_type({:long, value}) when is_integer(value) and value in -9_223_372_036_854_775_808..9_223_372_036_854_775_807, do: true
|
||||||
|
def check_type({:float, value}) when is_float(value), do: true
|
||||||
|
def check_type({:double, value}) when is_float(value), do: true
|
||||||
|
def check_type({:byte_array, values}) when is_list(values), do: Enum.all?(values, &is_integer/1)
|
||||||
|
def check_type({:string, value}) when is_binary(value), do: true
|
||||||
|
def check_type({:list, {type, values}}) when is_list(values), do: Enum.all?(values, &check_type({type, &1}))
|
||||||
|
def check_type({:compound, values}) when is_map(values), do: Enum.all?(values, fn {name, {type, value}} -> check_type({type, value}) end)
|
||||||
|
def check_type({:int_array, values}) when is_list(values), do: Enum.all?(values, &is_integer/1)
|
||||||
|
def check_type({:long_array, values}) when is_list(values), do: Enum.all?(values, &is_integer/1)
|
||||||
|
def check_type(_), do: false
|
||||||
|
|
||||||
defp type_id(:end), do: 0
|
defp type_id(:end), do: 0
|
||||||
defp type_id(:byte), do: 1
|
defp type_id(:byte), do: 1
|
||||||
defp type_id(:short), do: 2
|
defp type_id(:short), do: 2
|
||||||
|
@ -61,7 +61,7 @@ defmodule Amethyst.ConnectionState.Configuration do
|
|||||||
]
|
]
|
||||||
Macros.defpacket_clientbound :clientbound_known_packs, 0x0E, 767, [
|
Macros.defpacket_clientbound :clientbound_known_packs, 0x0E, 767, [
|
||||||
packs: {:array, [
|
packs: {:array, [
|
||||||
nameshape: :string,
|
namespace: :string,
|
||||||
id: :string,
|
id: :string,
|
||||||
version: :string
|
version: :string
|
||||||
]}
|
]}
|
||||||
@ -269,8 +269,9 @@ defmodule Amethyst.ConnectionState.Configuration do
|
|||||||
send(self(), {:set_state, Amethyst.ConnectionState.Play})
|
send(self(), {:set_state, Amethyst.ConnectionState.Play})
|
||||||
game = Application.fetch_env!(:amethyst, :default_game) |> Amethyst.GameCoordinator.find_or_create()
|
game = Application.fetch_env!(:amethyst, :default_game) |> Amethyst.GameCoordinator.find_or_create()
|
||||||
state = state |> Map.put(:game, game)
|
state = state |> Map.put(:game, game)
|
||||||
if Amethyst.Api.Game.login(game, state) == :reject do
|
if Amethyst.API.Game.login(game, state) == :reject do
|
||||||
send(self(), {:disconnect, "Default game rejected connection"})
|
send(self(), {:disconnect, "Default game rejected connection"})
|
||||||
|
:ok
|
||||||
else
|
else
|
||||||
send(self(), {:send_packet, %{
|
send(self(), {:send_packet, %{
|
||||||
packet_type: :login,
|
packet_type: :login,
|
||||||
@ -294,6 +295,7 @@ defmodule Amethyst.ConnectionState.Configuration do
|
|||||||
portal_cooldown: 0,
|
portal_cooldown: 0,
|
||||||
enforces_secure_chat: false
|
enforces_secure_chat: false
|
||||||
}})
|
}})
|
||||||
|
state
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
defmodule Amethyst.ConnectionState.Macros do
|
defmodule Amethyst.ConnectionState.Macros do
|
||||||
|
require Logger
|
||||||
defmacro defpacket_serverbound(name, id, version, signature) do
|
defmacro defpacket_serverbound(name, id, version, signature) do
|
||||||
quote do
|
quote do
|
||||||
def deserialize(unquote(id), unquote(version), data) do
|
def deserialize(unquote(id), unquote(version), data) do
|
||||||
@ -27,7 +28,11 @@ defmodule Amethyst.ConnectionState.Macros do
|
|||||||
defmacro defpacket_clientbound(name, id, version, signature) do
|
defmacro defpacket_clientbound(name, id, version, signature) do
|
||||||
quote do
|
quote do
|
||||||
def serialize(%{packet_type: unquote(name)} = packet, unquote(version)) do
|
def serialize(%{packet_type: unquote(name)} = packet, unquote(version)) do
|
||||||
Amethyst.Minecraft.Write.varint(unquote(id)) <> Amethyst.ConnectionState.Macros.write_signature(packet, unquote(signature))
|
if Amethyst.ConnectionState.Macros.check_type(packet, unquote(signature)) do
|
||||||
|
Amethyst.Minecraft.Write.varint(unquote(id)) <> Amethyst.ConnectionState.Macros.write_signature(packet, unquote(signature))
|
||||||
|
else
|
||||||
|
raise "Invalid packet type for #{unquote(name)}! Got #{inspect(packet)}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -56,11 +61,15 @@ defmodule Amethyst.ConnectionState.Macros do
|
|||||||
end
|
end
|
||||||
{:array, signature} ->
|
{:array, signature} ->
|
||||||
{[count], rest} = Read.start(rest) |> Read.varint() |> Read.stop()
|
{[count], rest} = Read.start(rest) |> Read.varint() |> Read.stop()
|
||||||
{items, rest} = Enum.reduce(1..count, {[], rest}, fn _, {acc, rest} ->
|
if count == 0 do
|
||||||
{item, rest} = read_signature(rest, signature)
|
{[[] | acc], rest, :reversed}
|
||||||
{[item | acc], rest}
|
else
|
||||||
end)
|
{items, rest} = Enum.reduce(1..count, {[], rest}, fn _, {acc, rest} ->
|
||||||
{[Enum.reverse(items) | acc], rest, :reversed}
|
{item, rest} = read_signature(rest, signature)
|
||||||
|
{[item | acc], rest}
|
||||||
|
end)
|
||||||
|
{[Enum.reverse(items) | acc], rest, :reversed}
|
||||||
|
end
|
||||||
t -> apply(Read, t, [{acc, rest, :reversed}])
|
t -> apply(Read, t, [{acc, rest, :reversed}])
|
||||||
end
|
end
|
||||||
end) |> Read.stop()
|
end) |> Read.stop()
|
||||||
@ -91,4 +100,56 @@ defmodule Amethyst.ConnectionState.Macros do
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_type(packet, signature) do
|
||||||
|
try do
|
||||||
|
Enum.all?(signature, fn {name, type} ->
|
||||||
|
case Map.get(packet, name, :missing) do
|
||||||
|
:missing -> throw {:missing, name}
|
||||||
|
value -> case type_matches(value, type) do
|
||||||
|
true -> true
|
||||||
|
false -> throw {:mismatch, name, value, type}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
catch
|
||||||
|
reason ->
|
||||||
|
Logger.debug("Found invalid packet type: #{inspect(reason)}")
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def type_matches(value, :bool) when is_boolean(value), do: true
|
||||||
|
def type_matches(value, :byte) when is_integer(value) and value in -128..127, do: true
|
||||||
|
def type_matches(value, :ubyte) when is_integer(value) and value in 0..255, do: true
|
||||||
|
def type_matches(value, :short) when is_integer(value) and value in -32768..32767, do: true
|
||||||
|
def type_matches(value, :ushort) when is_integer(value) and value in 0..65535, do: true
|
||||||
|
def type_matches(value, :int) when is_integer(value) and value in -2147483648..2147483647, do: true
|
||||||
|
def type_matches(value, :long) when is_integer(value) and value in -9223372036854775808..9223372036854775807, do: true
|
||||||
|
def type_matches(value, :float) when is_float(value), do: true
|
||||||
|
def type_matches(value, :double) when is_float(value), do: true
|
||||||
|
def type_matches(value, :varint) when is_integer(value) and value in -2147483648..2147483647, do: true
|
||||||
|
def type_matches(value, :varlong) when is_integer(value) and value in -9223372036854775808..9223372036854775807, do: true
|
||||||
|
def type_matches(value, :uuid) when is_binary(value) and byte_size(value) == 36, do: true
|
||||||
|
def type_matches(value, :string) when is_binary(value), do: true
|
||||||
|
def type_matches(value, :raw) when is_binary(value), do: true
|
||||||
|
def type_matches(value, :byte_array) when is_binary(value), do: true
|
||||||
|
def type_matches({x, y, z}, :position) when
|
||||||
|
is_integer(x) and x in -33554432..33554431 and
|
||||||
|
is_integer(y) and y in -2048..2047 and
|
||||||
|
is_integer(z) and z in -33554432..33554431, do: true
|
||||||
|
def type_matches(value, :nbt), do: Amethyst.NBT.Write.check_type(value)
|
||||||
|
def type_matches(value, :json) do
|
||||||
|
case Jason.encode(value) do
|
||||||
|
{:ok, _} -> true
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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, {:compound, signature}) when is_map(value), do: check_type(value, signature)
|
||||||
|
def type_matches(_, _) do
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user