This commit is contained in:
parent
5413708b29
commit
1ced941440
@ -34,7 +34,7 @@ alias ElixirSense.Log
|
||||
def start(socket, connstate, version) do
|
||||
{:ok, spawn(fn ->
|
||||
Process.set_label("ConnectionHandler for #{inspect(socket)}")
|
||||
loop(socket, connstate, version)
|
||||
loop(socket, connstate, version, %{})
|
||||
end)}
|
||||
end
|
||||
|
||||
@ -42,12 +42,12 @@ alias ElixirSense.Log
|
||||
def start_link(socket, connstate, version) do
|
||||
{:ok, spawn_link(fn ->
|
||||
Process.set_label("ConnectionHandler for #{inspect(socket)}")
|
||||
loop(socket, connstate, version)
|
||||
loop(socket, connstate, version, %{})
|
||||
end)}
|
||||
end
|
||||
|
||||
@spec loop(:gen_tcp.socket(), atom(), pos_integer()) :: no_return()
|
||||
defp loop(socket, connstate, version) do
|
||||
@spec loop(:gen_tcp.socket(), atom(), pos_integer(), map()) :: no_return()
|
||||
defp loop(socket, connstate, version, state) do
|
||||
receive do
|
||||
:closed ->
|
||||
Logger.info("Connection #{inspect(socket)} closed.")
|
||||
@ -57,38 +57,45 @@ alias ElixirSense.Log
|
||||
Process.exit(self(), :normal)
|
||||
{:set_state, newstate} ->
|
||||
Logger.debug("Switching to state #{newstate} from #{connstate}")
|
||||
loop(socket, newstate, version)
|
||||
loop(socket, newstate, version, state)
|
||||
{:set_version, newversion} ->
|
||||
Logger.debug("Switching to version #{newversion} from #{version}")
|
||||
loop(socket, connstate, newversion)
|
||||
loop(socket, connstate, newversion, state)
|
||||
{:send_packet, packet} ->
|
||||
Logger.debug("Sending packet #{inspect(packet)}")
|
||||
send_packet(socket, connstate, packet, version)
|
||||
loop(socket, connstate, version)
|
||||
loop(socket, connstate, version, state)
|
||||
after 0 ->
|
||||
receive do
|
||||
{:packet, id, data} ->
|
||||
handle_packet(id, data, connstate, version)
|
||||
loop(socket, connstate, version)
|
||||
state = handle_packet(id, data, connstate, version, state)
|
||||
loop(socket, connstate, version, state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_packet(id, data, connstate, version) do
|
||||
defp handle_packet(id, data, connstate, version, state) do
|
||||
try do
|
||||
packet = connstate.deserialize(id, version, data)
|
||||
case connstate.handle(packet, version) do
|
||||
:ok -> :ok
|
||||
case connstate.handle(packet, version, state) do
|
||||
:ok -> state
|
||||
{:error, reason} ->
|
||||
Logger.error("Error handling packet with ID #{id} in state #{connstate}: #{reason}")
|
||||
send(self(), {:disconnect, "Error handling packet #{id}: #{reason}"})
|
||||
_ ->
|
||||
Logger.warn("Unknown return value from handle_packet for packet #{id} in state #{connstate}")
|
||||
send(self(), {:disconnect, "Error handling packet #{id}:\n#{reason}"})
|
||||
state
|
||||
newstate ->
|
||||
if is_map(newstate) do
|
||||
newstate
|
||||
else
|
||||
Logger.warning("State change to #{newstate} is not a map! Did you forget to return :ok?")
|
||||
state
|
||||
end
|
||||
end
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("Error handling packet with ID #{id} in state #{connstate}: #{Exception.format(:error, e, __STACKTRACE__)}")
|
||||
send(self(), {:disconnect, "Error handling packet #{id}: #{Exception.format(:error, e, __STACKTRACE__)}"})
|
||||
send(self(), {:disconnect, "Error handling packet #{id}:\n#{e.message}"})
|
||||
state
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -135,6 +135,10 @@ defmodule Amethyst.Minecraft.Write do
|
||||
v -> bool(true) <> callback.(v)
|
||||
end
|
||||
end
|
||||
|
||||
def nbt(value) do
|
||||
Amethyst.NBT.Write.write_net(value)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Amethyst.Minecraft.Read do
|
||||
@ -259,4 +263,7 @@ defmodule Amethyst.Minecraft.Read do
|
||||
{[value], rest, :reversed} = string({[], data, :reversed})
|
||||
{[Jason.decode!(value) | acc], rest, :reversed}
|
||||
end
|
||||
def raw({acc, data, :reversed}) do
|
||||
{[data | acc], "", :reversed}
|
||||
end
|
||||
end
|
||||
|
115
apps/amethyst/lib/states/configuration.ex
Normal file
115
apps/amethyst/lib/states/configuration.ex
Normal file
@ -0,0 +1,115 @@
|
||||
# Amethyst - An experimental Minecraft server written in Elixir.
|
||||
# Copyright (C) 2024 KodiCraft
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
defmodule Amethyst.ConnectionState.Configuration do
|
||||
require Amethyst.ConnectionState.Macros
|
||||
alias Amethyst.ConnectionState.Macros
|
||||
|
||||
require Logger
|
||||
|
||||
@moduledoc """
|
||||
This module contains the packets and logic for the Configuration state.
|
||||
"""
|
||||
Macros.defpacket_clientbound :cookie_request, 0x00, 767, [identifier: :string]
|
||||
Macros.defpacket_clientbound :clientbound_plugin_message, 0x01, 767, [channel: :string, data: :raw]
|
||||
Macros.defpacket_clientbound :disconnect, 0x02, 767, [reason: :json]
|
||||
Macros.defpacket_clientbound :finish_configuration, 0x03, 767, []
|
||||
Macros.defpacket_clientbound :clientbound_keep_alive, 0x04, 767, [id: :long]
|
||||
Macros.defpacket_clientbound :ping, 0x05, 767, [id: :int]
|
||||
Macros.defpacket_clientbound :reset_chat, 0x06, 767, []
|
||||
Macros.defpacket_clientbound :registry_data, 0x07, 767, [
|
||||
id: :string,
|
||||
entries: {:array, [
|
||||
id: :string,
|
||||
data: {:optional, :nbt}
|
||||
]}
|
||||
]
|
||||
Macros.defpacket_clientbound :remove_resource_pack, 0x08, 767, [
|
||||
uuid: {:optional, :uuid}
|
||||
]
|
||||
Macros.defpacket_clientbound :add_resource_pack, 0x09, 767, [
|
||||
uuid: :uuid,
|
||||
url: :string,
|
||||
hash: :string,
|
||||
forced: :bool,
|
||||
prompt_message: {:optional, :string}
|
||||
]
|
||||
Macros.defpacket_clientbound :store_cookie, 0x0A, 767, [identifier: :string, payload: :byte_array]
|
||||
Macros.defpacket_clientbound :transfer, 0x0B, 767, [host: :string, port: :varint]
|
||||
Macros.defpacket_clientbound :feature_flags, 0x0C, 767, [flags: {:array, [flag: :string]}]
|
||||
Macros.defpacket_clientbound :update_tags, 0x0D, 767, [
|
||||
tags: {:array, [
|
||||
registry: :string,
|
||||
tags: {:array, [
|
||||
name: :string,
|
||||
entries: {:array, [id: :varint]}
|
||||
]}
|
||||
]}
|
||||
]
|
||||
Macros.defpacket_clientbound :clientbound_known_packs, 0x0E, 767, [
|
||||
packs: {:array, [
|
||||
nameshape: :string,
|
||||
id: :string,
|
||||
version: :string
|
||||
]}
|
||||
]
|
||||
Macros.defpacket_clientbound :custom_report_details, 0x0F, 767, [
|
||||
details: {:array, [
|
||||
title: :string,
|
||||
desctioption: :string
|
||||
]}
|
||||
]
|
||||
Macros.defpacket_clientbound :server_links, 0x10, 767, [
|
||||
links: {:array, [
|
||||
is_builtin: :bool,
|
||||
label: :string,
|
||||
url: :string
|
||||
]}
|
||||
]
|
||||
|
||||
Macros.defpacket_serverbound :client_information, 0x00, 767, [
|
||||
locale: :string,
|
||||
view_distance: :byte,
|
||||
chat_mode: :varint,
|
||||
chat_colors: :bool,
|
||||
displayed_skin_parts: :byte,
|
||||
main_hand: :varint,
|
||||
text_filtering: :bool,
|
||||
allow_server_listings: :bool
|
||||
]
|
||||
Macros.defpacket_serverbound :cookie_response, 0x01, 767, [
|
||||
key: :string,
|
||||
payload: {:optional, :byte_array}
|
||||
]
|
||||
Macros.defpacket_serverbound :serverbound_plugin_message, 0x02, 767, [channel: :string, data: :raw]
|
||||
Macros.defpacket_serverbound :acknowledge_finish_configuration, 0x03, 767, []
|
||||
Macros.defpacket_serverbound :serverbound_keep_alive, 0x04, 767, [id: :long]
|
||||
Macros.defpacket_serverbound :pong, 0x05, 767, [id: :int]
|
||||
Macros.defpacket_serverbound :resource_pack_response, 0x06, 767, [uuid: :uuid, result: :varint]
|
||||
Macros.defpacket_serverbound :serverbound_known_packs, 0x07, 767, [
|
||||
packs: {:array, [
|
||||
namespace: :string,
|
||||
id: :string,
|
||||
version: :string
|
||||
]}
|
||||
]
|
||||
|
||||
def disconnect(reason) do
|
||||
%{packet_type: :disconnect, reason: %{
|
||||
"text" => reason
|
||||
}}
|
||||
end
|
||||
end
|
@ -31,7 +31,7 @@ defmodule Amethyst.ConnectionState.Handshake do
|
||||
next: :varint
|
||||
]
|
||||
|
||||
def handle(%{packet_type: :handshake, version: 767, address: address, port: port, next: next}, 0) do
|
||||
def handle(%{packet_type: :handshake, version: 767, address: address, port: port, next: next}, 0, _state) do
|
||||
Logger.debug("Received handshake for #{address}:#{port} with version 767")
|
||||
case next do
|
||||
1 ->
|
||||
|
@ -23,7 +23,7 @@ defmodule Amethyst.ConnectionState.Login do
|
||||
@moduledoc """
|
||||
This module contains the packets and logic for the Login state.
|
||||
"""
|
||||
Macros.defpacket_clientbound :disconnect, 0x00, 767, [reason: :json]
|
||||
Macros.defpacket_clientbound :disconnect, 0x00, 767, [reason: :nbt]
|
||||
Macros.defpacket_clientbound :encryption_request, 0x01, 767, [
|
||||
server_id: :string,
|
||||
public_key: :byte_array,
|
||||
@ -60,10 +60,33 @@ defmodule Amethyst.ConnectionState.Login do
|
||||
Macros.defpacket_serverbound :login_acknowledged, 0x03, 767, []
|
||||
Macros.defpacket_serverbound :cookie_response, 0x04, 767, [identifier: :string, payload: {:optional, :byte_array}]
|
||||
|
||||
def handle(%{packet_type: :login_start, name: name, player_uuid: player_uuid}, 767, state) do
|
||||
Logger.debug("Received login start for #{name} with UUID #{player_uuid}")
|
||||
if Application.fetch_env!(:amethyst, :encryption) do
|
||||
raise RuntimeError, "Encryption is not currently supported"
|
||||
else
|
||||
send(self(), {:send_packet, %{
|
||||
packet_type: :login_success,
|
||||
uuid: player_uuid,
|
||||
username: name,
|
||||
properties: [],
|
||||
strict_error_handling: false
|
||||
}})
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def handle(%{packet_type: :login_acknowledged}, 767, _state) do
|
||||
Logger.debug("Received login acknowledged")
|
||||
send(self(), {:set_state, Amethyst.ConnectionState.Configuration})
|
||||
:ok
|
||||
end
|
||||
|
||||
def disconnect(reason) do
|
||||
%{packet_type: :disconnect, reason: %{
|
||||
"text" => "You have been disconnected:\n#{reason}",
|
||||
"color" => "red"
|
||||
%{packet_type: :disconnect, reason:
|
||||
{:compound, %{
|
||||
"text" => {:string, reason}
|
||||
}}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -29,7 +29,7 @@ defmodule Amethyst.ConnectionState.Status do
|
||||
Macros.defpacket_serverbound :status_request, 0x00, 767, []
|
||||
Macros.defpacket_serverbound :ping_request, 0x01, 767, [payload: :long]
|
||||
|
||||
def handle(%{packet_type: :status_request}, 767) do
|
||||
def handle(%{packet_type: :status_request}, 767, _state) do
|
||||
Logger.debug("Received status request")
|
||||
send(self(), {:send_packet, %{
|
||||
packet_type: :status_response,
|
||||
@ -45,7 +45,7 @@ defmodule Amethyst.ConnectionState.Status do
|
||||
:ok
|
||||
end
|
||||
|
||||
def handle(%{packet_type: :ping_request, payload: payload}, 767) do
|
||||
def handle(%{packet_type: :ping_request, payload: payload}, 767, _state) do
|
||||
Logger.debug("Received ping request")
|
||||
send(self(), {:send_packet, %{
|
||||
packet_type: :pong_response,
|
||||
|
Loading…
Reference in New Issue
Block a user