Progress on getting back up to speed
All checks were successful
Build & Test / nix-build (push) Successful in 1m32s
All checks were successful
Build & Test / nix-build (push) Successful in 1m32s
This commit is contained in:
parent
9ec63487c2
commit
4beb083dd6
@ -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}
|
||||||
|
@ -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)
|
||||||
|
61
apps/amethyst/lib/states/play.ex
Normal file
61
apps/amethyst/lib/states/play.ex
Normal 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
|
Loading…
Reference in New Issue
Block a user