Progress on getting back up to speed
All checks were successful
Build & Test / nix-build (push) Successful in 1m32s

This commit is contained in:
Kodi Craft 2024-09-06 19:53:48 +02:00
parent 9ec63487c2
commit 4beb083dd6
Signed by: kodi
GPG Key ID: 69D9EED60B242822
3 changed files with 230 additions and 0 deletions

View File

@ -130,6 +130,14 @@ defmodule Amethyst.ConnectionState.Configuration do
allow_server_listings: allow_server_listings allow_server_listings: allow_server_listings
}, 767, state) do }, 767, state) do
Logger.debug("Received client information") Logger.debug("Received client information")
send(self(), {:send_packet, %{
packet_type: :feature_flags,
flags: []
}})
send(self(), {:send_packet, %{
packet_type: :clientbound_known_packs,
packs: [%{namespace: "minecraft", id: "base", version: "1.21"}]
}})
state state
|> Map.put(:locale, locale) |> Map.put(:locale, locale)
|> Map.put(:view_distance, view_distance) |> Map.put(:view_distance, view_distance)
@ -141,6 +149,154 @@ defmodule Amethyst.ConnectionState.Configuration do
|> Map.put(:allow_server_listings, allow_server_listings) |> Map.put(:allow_server_listings, allow_server_listings)
end end
def handle(%{packet_type: :serverbound_known_packs, packs: _packs}, 767, _state) do
Logger.debug("Received known packs")
import Amethyst.NBT.Write
# TODO: Of course, the registries shouldn't be hard-coded
send(self(), {:send_packet, %{
packet_type: :registry_data,
id: "minecraft:dimension_type",
entries: [
%{id: "amethyst:basic", data: compound(%{
"has_skylight" => byte(1),
"has_ceiling" => byte(0),
"ultrawarm" => byte(0),
"natural" => byte(1),
"coordinate_scale" => float(1.0),
"bed_works" => byte(1),
"respawn_anchor_works" => byte(1),
"min_y" => int(0),
"height" => int(256),
"logical_height" => int(256),
"infiniburn" => string("#"),
"effects" => string("minecraft:overworld"),
"ambient_light" => float(0.0),
"piglin_safe" => byte(0),
"has_raids" => byte(1),
"monster_spawn_light_level" => int(0),
"monster_spawn_block_light_limit" => int(0)
})}
]
}})
send(self(), {:send_packet, %{
packet_type: :registry_data,
id: "minecraft:painting_variant", entries: [
%{id: "minecraft:kebab", data: compound(%{
"asset_id" => string("minecraft:kebab"),
"height" => int(1),
"width" => int(1),
})}
]
}})
send(self(), {:send_packet, %{
packet_type: :registry_data,
id: "minecraft:wolf_variant",
entries: [
%{id: "minecraft:wolf_ashen", data: compound(%{
"wild_texture" => string("minecraft:entity/wolf/wolf_ashen"),
"tame_texture" => string("minecraft:entity/wolf/wolf_ashen_tame"),
"angry_texture" => string("minecraft:entity/wolf/wolf_ashen_angry"),
"biomes" => string("amethyst:basic"),
})}
]
}})
# https://gist.github.com/WinX64/ab8c7a8df797c273b32d3a3b66522906 minecraft:plains
basic_biome = compound(%{
"effects" => compound(%{
"sky_color" => int(7907327),
"water_fog_color" => int(329011),
"fog_color" => int(12638463),
"water_color" => int(4159204),
"mood_sound" => compound(%{
"tick_delay" => int(6000),
"offset" => float(2.0),
"sound" => string("minecraft:ambient.cave"),
"block_search_extent" => int(8)
}),
}),
"has_precipitation" => byte(1),
"temperature" => float(0.8),
"downfall" => float(0.4),
})
send(self(), {:send_packet, %{
packet_type: :registry_data,
id: "minecraft:worldgen/biome",
entries: [
%{id: "amethyst:basic", data: basic_biome},
%{id: "minecraft:plains", data: basic_biome}
]
}})
# this game sucks
generic_damage = compound(%{
"scaling" => string("when_caused_by_living_non_player"),
"exhaustion" => float(0.0),
"message_id" => string("generic")
})
send(self(), {:send_packet, %{
packet_type: :registry_data,
id: "minecraft:damage_type",
entries: [
%{id: "minecraft:in_fire", data: generic_damage},
%{id: "minecraft:campfire", data: generic_damage},
%{id: "minecraft:lightning_bolt", data: generic_damage},
%{id: "minecraft:on_fire", data: generic_damage},
%{id: "minecraft:lava", data: generic_damage},
%{id: "minecraft:cramming", data: generic_damage},
%{id: "minecraft:drown", data: generic_damage},
%{id: "minecraft:starve", data: generic_damage},
%{id: "minecraft:cactus", data: generic_damage},
%{id: "minecraft:fall", data: generic_damage},
%{id: "minecraft:fly_into_wall", data: generic_damage},
%{id: "minecraft:out_of_world", data: generic_damage},
%{id: "minecraft:generic", data: generic_damage},
%{id: "minecraft:magic", data: generic_damage},
%{id: "minecraft:wither", data: generic_damage},
%{id: "minecraft:dragon_breath", data: generic_damage},
%{id: "minecraft:dry_out", data: generic_damage},
%{id: "minecraft:sweet_berry_bush", data: generic_damage},
%{id: "minecraft:freeze", data: generic_damage},
%{id: "minecraft:stalagmite", data: generic_damage},
%{id: "minecraft:outside_border", data: generic_damage},
%{id: "minecraft:generic_kill", data: generic_damage},
]
}})
send(self(), {:send_packet, %{packet_type: :finish_configuration}})
:ok
end
def handle(%{packet_type: :acknowledge_finish_configuration}, 767, state) do
Logger.debug("Received acknowledge finish configuration")
send(self(), {:set_state, Amethyst.ConnectionState.Play})
game = Application.fetch_env!(:amethyst, :default_game) |> Amethyst.GameCoordinator.find_or_create()
state = state |> Map.put(:game, game)
if Amethyst.Api.Game.login(game, state) == :reject do
send(self(), {:disconnect, "Default game rejected connection"})
else
send(self(), {:send_packet, %{
packet_type: :login,
entity_id: 0,
is_hardcore: false,
dimensions: [%{name: "minecraft:overworld"}],
max_players: 0,
view_distance: 16,
simulation_distance: 16,
reduced_debug_info: false,
enable_respawn_screen: true,
do_limited_crafting: false,
dimension_type: 0,
dimension_name: "minecraft:overworld",
hashed_seed: 0,
game_mode: 3,
previous_game_mode: -1,
is_debug: false,
is_flat: false,
death_location: nil,
portal_cooldown: 0,
enforces_secure_chat: false
}})
end
end
def disconnect(reason) do def disconnect(reason) do
%{packet_type: :disconnect, reason: {:compound, %{ %{packet_type: :disconnect, reason: {:compound, %{
"text" => {:string, reason} "text" => {:string, reason}

View File

@ -39,6 +39,14 @@ defmodule Amethyst.ConnectionState.Macros do
names = Enum.map(signature, fn {name, _type} -> name end) names = Enum.map(signature, fn {name, _type} -> name end)
{got, rest} = Enum.reduce(signature, Read.start(data), fn {_name, type}, {acc, rest, :reversed} -> {got, rest} = Enum.reduce(signature, Read.start(data), fn {_name, type}, {acc, rest, :reversed} ->
case type do case type do
{:optional, {:compound, signature}} ->
{[exists], rest} = Read.start(rest) |> Read.bool() |> Read.stop()
if exists do
{item, rest} = read_signature(rest, signature)
{[item | acc], rest, :reversed}
else
{[nil | acc], rest, :reversed}
end
{:optional, t} -> {:optional, t} ->
{[exists], rest} = Read.start(rest) |> Read.bool() |> Read.stop() {[exists], rest} = Read.start(rest) |> Read.bool() |> Read.stop()
if exists do if exists do
@ -64,6 +72,11 @@ defmodule Amethyst.ConnectionState.Macros do
data = Enum.reduce(signature, "", fn {name, type}, acc -> data = Enum.reduce(signature, "", fn {name, type}, acc ->
#acc <> apply(Write, type, [Map.get(packet, name)]) #acc <> apply(Write, type, [Map.get(packet, name)])
case type do case type do
{:optional, {:compound, signature}} ->
case Map.get(packet, name) do
nil -> acc <> Write.bool(false)
_ -> acc <> Write.bool(true) <> write_signature(Map.get(packet, name), signature)
end
{:optional, t} -> {:optional, t} ->
case Map.get(packet, name) do case Map.get(packet, name) do
nil -> acc <> Write.bool(false) nil -> acc <> Write.bool(false)

View File

@ -0,0 +1,61 @@
# 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.Play do
require Amethyst.ConnectionState.Macros
alias Amethyst.ConnectionState.Macros
require Logger
@moduledoc """
This module contains the packets and logic for the Play state.
"""
Macros.defpacket_clientbound :disconnect, 0x1D, 767, [reason: :nbt]
Macros.defpacket_clientbound :login, 0x2B, 767, [
entity_id: :int,
is_hardcore: :bool,
dimensions: {:array, [name: :string]},
max_players: :varint,
view_distance: :varint,
simulation_distance: :varint,
reduced_debug_info: :bool,
enable_respawn_screen: :bool,
do_limited_crafting: :bool,
dimension_type: :varint,
dimension_name: :string,
hashed_seed: :long,
game_mode: :ubyte,
previous_game_mode: :byte,
is_debug: :bool,
is_flat: :bool,
death_location: {:optional, {:compound, [
dimension: :string,
location: :pos
]}},
portal_cooldown: :varint,
enforces_secure_chat: :bool,
]
def disconnect(reason) do
%{
packet_type: :disconnect,
reason: {:compound, %{
"text" => {:string, reason}
}}
}
end
end