Implement rudimentary keepalive
All checks were successful
Build & Test / nix-build (pull_request) Successful in 2m35s
Build & Test / nix-build (push) Successful in 2m38s

This commit is contained in:
Kodi Craft 2024-10-04 10:33:41 +02:00
parent fb0099352b
commit 288ead3e9b
Signed by: kodi
GPG Key ID: 69D9EED60B242822
2 changed files with 30 additions and 1 deletions

View File

@ -269,6 +269,7 @@ defmodule Amethyst.ConnectionState.Configuration do
def handle(%{packet_type: :acknowledge_finish_configuration}, 767, state) do def handle(%{packet_type: :acknowledge_finish_configuration}, 767, state) do
Logger.debug("Received acknowledge finish configuration") Logger.debug("Received acknowledge finish configuration")
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)
login = Amethyst.Game.login(game, state) login = Amethyst.Game.login(game, state)
@ -309,7 +310,11 @@ defmodule Amethyst.ConnectionState.Configuration do
chunk_z: div(floor(z), 16) chunk_z: div(floor(z), 16)
}}) }})
send(self(), {:set_position, {x, y, z}}) send(self(), {:set_position, {x, y, z}})
state # Begin keepalive loop
# TODO: Put it under some supervisor
me = self()
pid = spawn(fn -> Amethyst.ConnectionState.Play.keepalive_loop(me) end)
state |> Map.put(:keepalive, pid)
end end
end end

View File

@ -24,6 +24,7 @@ defmodule Amethyst.ConnectionState.Play do
This module contains the packets and logic for the Play state. This module contains the packets and logic for the Play state.
""" """
Macros.defpacket_clientbound :disconnect, 0x1D, 767, [reason: :nbt] Macros.defpacket_clientbound :disconnect, 0x1D, 767, [reason: :nbt]
Macros.defpacket_clientbound :keep_alive, 0x26, 767, [id: :long]
Macros.defpacket_clientbound :chunk_data_and_update_light, 0x27, 767, [ Macros.defpacket_clientbound :chunk_data_and_update_light, 0x27, 767, [
chunk_x: :int, chunk_x: :int,
chunk_z: :int, chunk_z: :int,
@ -157,6 +158,7 @@ defmodule Amethyst.ConnectionState.Play do
Macros.defpacket_serverbound :confirm_teleportation, 0x00, 767, [teleport_id: :varint] Macros.defpacket_serverbound :confirm_teleportation, 0x00, 767, [teleport_id: :varint]
Macros.defpacket_serverbound :serverbound_plugin_message, 0x12, 767, [channel: :string, data: :raw] Macros.defpacket_serverbound :serverbound_plugin_message, 0x12, 767, [channel: :string, data: :raw]
Macros.defpacket_serverbound :keep_alive, 0x18, 767, [id: :long]
Macros.defpacket_serverbound :set_player_position, 0x1A, 767, [ Macros.defpacket_serverbound :set_player_position, 0x1A, 767, [
x: :double, x: :double,
feet_y: :double, feet_y: :double,
@ -231,6 +233,28 @@ defmodule Amethyst.ConnectionState.Play do
end end
end end
def handle(%{packet_type: :keep_alive, id: id}, 767, state) do
ka = state |> Map.get(:keepalive)
send(ka, {:respond, id})
:ok
end
# This function should be started on a new task under the connection handler
# and is responsible for keepalive logic.
def keepalive_loop(player) do
Process.link(player) # Is it fine to do this on loop?
<<id::32>> = :rand.bytes(4)
Logger.debug("Sending keepalive...")
send(player, {:send_packet, %{packet_type: :keep_alive, id: id}})
receive do
{:respond, ^id} ->
:timer.sleep(250)
keepalive_loop(player)
after
15_000 ->
send(player, {:disconnect, "Timed out! Connection overloaded?"})
end
end
def disconnect(reason) do def disconnect(reason) do
%{ %{
packet_type: :disconnect, packet_type: :disconnect,