amethyst/lib/servers/play.ex

80 lines
3.0 KiB
Elixir
Raw Normal View History

2024-07-21 01:59:57 +02:00
# 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.Server.Play do
@moduledoc """
This module contains the logic for the Play stage of the server.
"""
require Logger
use Amethyst.Server
alias Amethyst.Minecraft.Read
alias Amethyst.Minecraft.Write
@impl true
def init(state) do
state
end
## DESERIALIZATION
@impl true
def deserialize(type, _) do
raise RuntimeError, "Got unknown packet type #{type}!"
end
## SERIALIZATION
@impl true
2024-07-21 03:13:30 +02:00
# Login https://wiki.vg/Protocol#Login_(play)
def serialize({:login, eid, hardcore, dimensions,
max_players, view_distance, simulation_distance,
reduce_debug, enable_respawn_screen, limited_crafting,
dim_type, dim_name, hashed_seed, gamemode, prev_gm,
is_debug, is_flat, death_loc, portal_cooldown, enforce_chat}) do
# TODO: this singlehandedly made me regret not making the write API better, please rework :(
2024-07-21 03:26:10 +02:00
Write.varint(0x2B) <>
2024-07-21 03:13:30 +02:00
<<eid::big-signed-32>> <> if(hardcore, do: <<1::big-8>>, else: <<0::big-8>>) <>
Write.varint(length(dimensions)) <> Enum.reduce(dimensions, "", fn dim, acc -> acc <> Write.string(dim) end) <>
Write.varint(max_players) <> Write.varint(view_distance) <> Write.varint(simulation_distance) <> if(reduce_debug, do: <<1::big-8>>, else: <<0::big-8>>) <>
if(enable_respawn_screen, do: <<1::big-8>>, else: <<0::big-8>>)
if(limited_crafting, do: <<1::big-8>>, else: <<0::big-8>>) <> Write.varint(dim_type) <> Write.string(dim_name) <>
hashed_seed <> <<gamemode_id(gamemode)::unsigned-big-8>> <> <<gamemode_id(prev_gm)::signed-big-8>> <>
if(is_debug, do: <<1::big-8>>, else: <<0::big-8>>) <> if(is_flat, do: <<1::big-8>>, else: <<0::big-8>>) <>
if(death_loc == nil, do: <<0::big-8>>, else: <<1::big-8>> <> Write.string(elem(death_loc, 0)) <> Write.position(elem(death_loc, 1))) <>
Write.varint(portal_cooldown) <> if(enforce_chat, do: <<1::big-8>>, else: <<0::big-8>>)
end
2024-07-21 01:59:57 +02:00
def serialize(packet) do
raise ArgumentError, "Tried serializing unknown packet #{inspect(packet)}"
end
## HANDLING
@impl true
def handle(tuple, _, state) do
Logger.error("Unhandled but known packet #{elem(tuple, 0)}")
{:unhandled, state}
end
2024-07-21 03:13:30 +02:00
defp gamemode_id(gm) do
case gm do
nil -> -1
:survival -> 0
:creative -> 1
:adventure -> 2
:spectator -> 3
end
end
2024-07-21 01:59:57 +02:00
end