diff --git a/lib/data.ex b/lib/data.ex index 239e33a..8a8aedb 100644 --- a/lib/data.ex +++ b/lib/data.ex @@ -101,6 +101,28 @@ defmodule Amethyst.Minecraft.Write do def position({x, y, z}) do <> end + + @doc """ + Writes a list of elements with the given `callback` function. This does not + prefix the list with a length, remember to do that yourself if needed. + + iex> Amethyst.Minecraft.Write.list([1, 2, 3, 4], &Amethyst.Minecraft.Write.byte/1) + <<1, 2, 3, 4>> + """ + def list(list, callback) do + Enum.reduce(list, "", &(&2 <> callback.(&1))) + end + + @doc """ + Shorthand function for writing a value which may not be present. If `value` is `nil`, + writes `false`, otherwise writes `true` followed by the value using `callback`. + """ + def option(value, callback) do + case value do + nil -> bool(false) + v -> bool(true) <> callback.(v) + end + end end defmodule Amethyst.Minecraft.Read do diff --git a/lib/servers/configuration.ex b/lib/servers/configuration.ex index 2224982..7457e68 100644 --- a/lib/servers/configuration.ex +++ b/lib/servers/configuration.ex @@ -143,16 +143,12 @@ defmodule Amethyst.Server.Configuration do end # Remove Resource Pack https://wiki.vg/Protocol#Remove_Resource_Pack_(configuration) def serialize({:remove_resource_pack, id}) do - if id == nil do - Write.varint(0x08) <> <<0x00>> - else - Write.varint(0x08) <> <<0x01>> <> Write.string(id) - end + Write.option(id, &Write.string/1) end # Add Resource Pack https://wiki.vg/Protocol#Add_Resource_Pack_(configuration) def serialize({:add_resource_pack, id, url, hash, forced, msg}) do Write.varint(0x09) <> Write.string(id) <> Write.string(url) <> Write.string(hash) <> - if(forced, do: <<0x01>>, else: <<0x00>>) <> if(msg == nil, do: <<0x00>>, else: <<0x01>> <> Write.string(msg)) + Write.bool(forced) <> Write.option(msg, &Write.string/1) end # Store Cookie https://wiki.vg/Protocol#Store_Cookie_(configuration) def serialize({:store_cookie, id, data}) do @@ -164,7 +160,7 @@ defmodule Amethyst.Server.Configuration do end # Feature Flags https://wiki.vg/Protocol#Feature_Flags def serialize({:feature_flags, flags}) do - Write.varint(0x0C) <> Write.varint(length(flags)) <> Enum.reduce(flags, "", fn id, acc -> acc <> Write.string(id) end) + Write.varint(0x0C) <> Write.varint(length(flags)) <> Write.list(flags, &Write.string/1) end # Update Tags https://wiki.vg/Protocol#Update_Tags def serialize({:update_tags, tags}) do @@ -174,19 +170,17 @@ defmodule Amethyst.Server.Configuration do # Clientbound Known Packs https://wiki.vg/Protocol#Clientbound_Known_Packs def serialize({:clientbound_known_packs, packs}) do Write.varint(0x0E) <> Write.varint(length(packs)) <> - Enum.reduce(packs, "", fn {namespace, id, version}, acc -> acc <> Write.string(namespace) <> Write.string(id) <> Write.string(version) end) + Write.list(packs, fn {namespace, id, version} -> Write.string(namespace) <> Write.string(id) <> Write.string(version) end) end # Custom Report Details https://wiki.vg/Protocol#Custom_Report_Details def serialize({:custom_report_details, details}) do Write.varint(0x0F) <> Write.varint(length(details)) <> - Enum.reduce(details, "", fn {id, data}, acc -> acc <> Write.string(id) <> Write.string(data) end) + Write.list(details, fn {id, data} -> Write.string(id) <> Write.string(data) end) end # Server Links https://wiki.vg/Protocol#Server_Links_(configuration) def serialize({:server_links, links}) do Write.varint(0x10) <> Write.varint(length(links)) <> - Enum.reduce(links, "", fn {label, url}, acc -> - acc <> serialize_link_label(label) <> Write.string(url) - end) + Write.list(links, fn {label, url} -> serialize_link_label(label) <> Write.string(url) end) end def serialize(packet) do raise ArgumentError, "Tried serializing unknown packet #{inspect(packet)}" @@ -196,8 +190,10 @@ defmodule Amethyst.Server.Configuration do acc <> Write.string(id) <> Write.varint(length(elements)) <> serialize_elements(elements) end defp serialize_elements(elements) do - Enum.reduce(elements, "", fn {id, ids}, acc -> acc <> Write.string(id) <> Write.varint(length(ids)) <> - Enum.reduce(ids, "", fn id, acc -> acc <> Write.varint(id) end) end) + Write.list(elements, fn {id, ids} -> + Write.string(id) <> Write.varint(length(ids)) <> + Write.list(ids, &Write.varint/1) + end) end defp serialize_link_label(:bug_report) do <<0x01>> <> Write.varint(0x00)