Implement registry_data
All checks were successful
Build & Test / nix-build (push) Successful in 1m39s
All checks were successful
Build & Test / nix-build (push) Successful in 1m39s
This commit is contained in:
parent
1cfb5384dc
commit
0c94bab3e4
117
lib/nbt.ex
Normal file
117
lib/nbt.ex
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# 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.NBT.Write do
|
||||||
|
@moduledoc """
|
||||||
|
This module contains the logic for writing NBT data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def write(name, {type, value}) do
|
||||||
|
<<type_id(type)::size(8), payload(:string, name)::binary, payload(type, value)::binary>>
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_net({type, value}) do
|
||||||
|
<<type_id(type)::size(8), payload(type, value)::binary>>
|
||||||
|
end
|
||||||
|
|
||||||
|
defp type_id(:end), do: 0
|
||||||
|
defp type_id(:byte), do: 1
|
||||||
|
defp type_id(:short), do: 2
|
||||||
|
defp type_id(:int), do: 3
|
||||||
|
defp type_id(:long), do: 4
|
||||||
|
defp type_id(:float), do: 5
|
||||||
|
defp type_id(:double), do: 6
|
||||||
|
defp type_id(:byte_array), do: 7
|
||||||
|
defp type_id(:string), do: 8
|
||||||
|
defp type_id(:list), do: 9
|
||||||
|
defp type_id(:compound), do: 10
|
||||||
|
defp type_id(:int_array), do: 11
|
||||||
|
defp type_id(:long_array), do: 12
|
||||||
|
|
||||||
|
defp payload(:byte, value), do: <<value::size(8)-big>>
|
||||||
|
defp payload(:short, value), do: <<value::size(16)-big>>
|
||||||
|
defp payload(:int, value), do: <<value::size(32)-big>>
|
||||||
|
defp payload(:long, value), do: <<value::size(64)-big>>
|
||||||
|
defp payload(:float, value), do: <<value::size(32)-float>>
|
||||||
|
defp payload(:double, value), do: <<value::size(64)-float>>
|
||||||
|
defp payload(:byte_array, values), do: <<length(values)::size(32)-big>> <> Enum.map_join(values, "", &payload(:byte, &1))
|
||||||
|
defp payload(:string, value), do: <<byte_size(value)::size(16)-big-unsigned>> <> value
|
||||||
|
defp payload(:list, {type, values}), do: <<type_id(type)::size(8)>> <> <<length(values)::size(32)-big>> <> Enum.map_join(values, "", &payload(type, &1))
|
||||||
|
defp payload(:compound, values), do: Enum.map_join(values, "", fn {name, {type, value}} -> write(name, {type, value}) end) <> <<0::size(8)>>
|
||||||
|
defp payload(:int_array, values), do: <<length(values)::size(32)-big>> <> Enum.map_join(values, "", &payload(:int, &1))
|
||||||
|
defp payload(:long_array, values), do: <<length(values)::size(32)-big>> <> Enum.map_join(values, "", &payload(:long, &1))
|
||||||
|
|
||||||
|
defmacro byte(value) do
|
||||||
|
quote do
|
||||||
|
{:byte, unquote(value)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro short(value) do
|
||||||
|
quote do
|
||||||
|
{:short, unquote(value)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro int(value) do
|
||||||
|
quote do
|
||||||
|
{:int, unquote(value)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro long(value) do
|
||||||
|
quote do
|
||||||
|
{:long, unquote(value)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro float(value) do
|
||||||
|
quote do
|
||||||
|
{:float, unquote(value)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro double(value) do
|
||||||
|
quote do
|
||||||
|
{:double, unquote(value)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro byte_array(values) do
|
||||||
|
quote do
|
||||||
|
{:byte_array, unquote(values)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro string(value) do
|
||||||
|
quote do
|
||||||
|
{:string, unquote(value)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro list(type, values) do
|
||||||
|
quote do
|
||||||
|
{:list, {unquote(type), unquote(values)}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro compound(values) do
|
||||||
|
quote do
|
||||||
|
{:compound, unquote(values)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro int_array(values) do
|
||||||
|
quote do
|
||||||
|
{:int_array, unquote(values)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defmacro long_array(values) do
|
||||||
|
quote do
|
||||||
|
{:long_array, unquote(values)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -138,8 +138,15 @@ defmodule Amethyst.Server.Configuration do
|
|||||||
Write.varint(0x06)
|
Write.varint(0x06)
|
||||||
end
|
end
|
||||||
# Registry Data https://wiki.vg/Protocol#Registry_Data
|
# Registry Data https://wiki.vg/Protocol#Registry_Data
|
||||||
def serialize({:registry_data, _id, _entries}) do
|
def serialize({:registry_data, id, entries}) do
|
||||||
raise ArgumentError, "Packet 'Registry Data' is not yet implemented"
|
Write.varint(0x07) <> Write.string(id) <> Write.varint(length(entries)) <> Enum.map_join(entries, "", fn {name, nbt} ->
|
||||||
|
Write.string(name) <>
|
||||||
|
if nbt == nil do
|
||||||
|
Write.bool(false)
|
||||||
|
else
|
||||||
|
Write.bool(true) <> Amethyst.NBT.Write.write_net(nbt)
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
# Remove Resource Pack https://wiki.vg/Protocol#Remove_Resource_Pack_(configuration)
|
# Remove Resource Pack https://wiki.vg/Protocol#Remove_Resource_Pack_(configuration)
|
||||||
def serialize({:remove_resource_pack, id}) do
|
def serialize({:remove_resource_pack, id}) do
|
||||||
@ -239,13 +246,82 @@ defmodule Amethyst.Server.Configuration do
|
|||||||
# TODO: Here we should create the game handling task for this player and give it
|
# TODO: Here we should create the game handling task for this player and give it
|
||||||
# this data.
|
# this data.
|
||||||
transmit({:clientbound_plugin_message, "minecraft:brand", Write.string("amethyst")}, client)
|
transmit({:clientbound_plugin_message, "minecraft:brand", Write.string("amethyst")}, client)
|
||||||
transmit({:clientbound_known_packs, [{"minecraft", "core", "1.21"}]}, client)
|
transmit({:clientbound_known_packs, [{"minecraft", "core", "1.21"}, {"minecraft", "dimension_type", "1.21"}]}, client)
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
# Serverbound Known Packs https://wiki.vg/Protocol#Serverbound_Known_Packs
|
# Serverbound Known Packs https://wiki.vg/Protocol#Serverbound_Known_Packs
|
||||||
def handle({:serverbound_known_packs, _packs}, client, state) do
|
def handle({:serverbound_known_packs, _packs}, client, state) do
|
||||||
# L + ratio + don't care + didn't ask + finish configuration
|
# L + ratio + don't care + didn't ask + finish configuration
|
||||||
# TODO: we should send registries i think? does amethyst need to deal with vanilla registries at all? god only knows
|
import Amethyst.NBT.Write
|
||||||
|
# TODO: This shouldn't be hard-coded but we obviously don't know what we will need until we have game handling
|
||||||
|
# This can at least be followed as a "minimum" of what we need to send for the client not to complain
|
||||||
|
transmit({:registry_data, "minecraft:dimension_type", [{"amethyst:basic", 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)
|
||||||
|
})}]}, client)
|
||||||
|
transmit({:registry_data, "minecraft:painting_variant", [{"minecraft:kebab", compound(%{
|
||||||
|
"asset_id" => string("minecraft:kebab"),
|
||||||
|
"height" => int(1),
|
||||||
|
"width" => int(1),
|
||||||
|
})}]}, client)
|
||||||
|
transmit({:registry_data, "minecraft:wolf_variant", [{"minecraft:wolf_ashen", 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"),
|
||||||
|
})}]}, client)
|
||||||
|
# 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),
|
||||||
|
})
|
||||||
|
transmit({:registry_data, "minecraft:worldgen/biome", [
|
||||||
|
{"amethyst:basic", basic_biome}, {"minecraft:plains", basic_biome}
|
||||||
|
]}, client)
|
||||||
|
# holy fucking shit
|
||||||
|
generic_damage = compound(%{
|
||||||
|
"scaling" => string("when_caused_by_living_non_player"),
|
||||||
|
"exhaustion" => float(0.0),
|
||||||
|
"message_id" => string("generic")
|
||||||
|
})
|
||||||
|
transmit({:registry_data, "minecraft:damage_type", [
|
||||||
|
{"minecraft:in_fire", generic_damage}, {"minecraft:campfire", generic_damage}, {"minecraft:lightning_bolt", generic_damage},
|
||||||
|
{"minecraft:on_fire", generic_damage}, {"minecraft:lava", generic_damage}, {"minecraft:hot_floor", generic_damage},
|
||||||
|
{"minecraft:in_wall", generic_damage}, {"minecraft:cramming", generic_damage}, {"minecraft:drown", generic_damage},
|
||||||
|
{"minecraft:starve", generic_damage}, {"minecraft:cactus", generic_damage}, {"minecraft:fall", generic_damage},
|
||||||
|
{"minecraft:fly_into_wall", generic_damage}, {"minecraft:out_of_world", generic_damage}, {"minecraft:generic", generic_damage},
|
||||||
|
{"minecraft:magic", generic_damage}, {"minecraft:wither", generic_damage}, {"minecraft:dragon_breath", generic_damage},
|
||||||
|
{"minecraft:dry_out", generic_damage}, {"minecraft:sweet_berry_bush", generic_damage}, {"minecraft:freeze", generic_damage},
|
||||||
|
{"minecraft:stalagmite", generic_damage}, {"minecraft:outside_border", generic_damage}, {"minecraft:generic_kill", generic_damage},
|
||||||
|
]}, client)
|
||||||
transmit({:finish_configuration}, client)
|
transmit({:finish_configuration}, client)
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user