Attempt at implementing versioned block registry
All checks were successful
Build & Test / nix-build (push) Successful in 1m47s

This commit is contained in:
Kodi Craft 2024-10-16 09:58:24 +02:00
parent e8f0e1b4c0
commit 4a387ff296
Signed by: kodi
GPG Key ID: 69D9EED60B242822
3 changed files with 51 additions and 26 deletions

View File

@ -31,18 +31,7 @@ defmodule Amethyst.Application do
child_spec: DynamicSupervisor.child_spec([]),
name: Amethyst.GameMetaSupervisor
},
{PartitionSupervisor,
child_spec: Amethyst.BlockRegistry.child_spec(%{}),
name: Amethyst.BlockRegistry},
Supervisor.child_spec(
{Task, fn ->
# TODO: not this
Amethyst.DataGenerator.generate_and_populate_data(
:latest,
"/tmp/server.jar",
"/tmp/amethyst-generated")
end},
id: Amethyst.DataGenerator)
{Registry, keys: :unique, name: Amethyst.BlockStateRegistry},
]
children = case Application.fetch_env!(:amethyst, :port) do

View File

@ -14,7 +14,7 @@
# 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.BlockRegistry do
defmodule Amethyst.BlockStates do
use GenServer
@moduledoc """
GenServer which can be populated with block states and their corresponding IDs.
@ -22,8 +22,8 @@ defmodule Amethyst.BlockRegistry do
"""
require Logger
def start_link(map) do
GenServer.start_link(__MODULE__, map)
def start_link(map, name) do
GenServer.start_link(__MODULE__, map, name: name)
end
def init(map) do
@ -52,22 +52,48 @@ defmodule Amethyst.BlockRegistry do
Adds a block state to the registry.
## Parameters
- `version` - The Minecraft version
- `id` - The block identifier
- `bs` - The block state
- `bsi` - The block state ID
"""
@spec add(String.t(), map(), integer()) :: :ok
def add(id, bs, bsi) do
GenServer.cast({:via, PartitionSupervisor, {__MODULE__, id}}, {:add, id, bs, bsi})
@spec add(String.t(), String.t(), map(), integer()) :: :ok
def add(version, id, bs, bsi) do
ps = {:via, Registry, {Amethyst.BlockStateRegistry, version}}
GenServer.cast({:via, PartitionSupervisor, {ps, id}}, {:add, id, bs, bsi})
end
@doc """
Gets the block state ID for a given block identifier and block state.
If no data is known for this version, errors. Prefer using `try_get/3`
if you can wait for the data to be loaded.
- `version` - The Minecraft version
- `id` - The block identifier
- `bs` - The block state, nil if the block has no states
"""
@spec get(String.t(), map() | nil) :: integer() | nil
def get(id, bs \\ %{}) do
GenServer.call({:via, PartitionSupervisor, {__MODULE__, id}}, {:get, id, bs})
@spec get(String.t(), String.t(), map() | nil) :: integer() | nil
def get(version, id, bs \\ %{}) do
ps = {:via, Registry, {Amethyst.BlockStateRegistry, version}}
GenServer.call({:via, PartitionSupervisor, {ps, id}}, {:get, id, bs})
end
@doc """
Tries to get the block state ID for a given block identifier and block state.
If no data is known for this version, it will block until the data is loaded.
- `version` - The Minecraft version
- `id` - The block identifier
- `bs` - The block state, nil if the block has no states
"""
@spec try_get(String.t(), String.t(), map() | nil) :: integer() | nil
def try_get(version, id, bs \\ %{}) do
case Registry.lookup(Amethyst.BlockStateRegistry, version) do
[{_pid, _}] ->
ps = {:via, Registry, {Amethyst.BlockStateRegistry, version}}
GenServer.call({:via, PartitionSupervisor, {ps, id}}, {:get, id, bs})
[] ->
Logger.warning("BlockStateRegistry doesn't exist for version #{version}, generating it now!")
Amethyst.DataGenerator.generate_and_populate_data(version, "/tmp/minecraft_server_#{version}.jar", "/tmp/minecraft_data_#{version}")
try_get(version, id, bs)
end
end
end

View File

@ -75,8 +75,8 @@ defmodule Amethyst.DataGenerator do
end
end
@spec populate_blockregistry(String.t()) :: :ok | {:error, term}
def populate_blockregistry(data_path) do
@spec populate_blockstates(String.t(), String.t()) :: :ok | {:error, term}
def populate_blockstates(data_path, version) do
block_file = Path.join([data_path, "reports", "blocks.json"])
case File.read(block_file) do
{:ok, data} ->
@ -84,8 +84,8 @@ defmodule Amethyst.DataGenerator do
{:ok, blocks} ->
Enum.each(blocks, fn {id, %{"states" => states}} ->
Enum.each(states, fn
%{"id" => bsi, "properties" => props} -> Amethyst.BlockRegistry.add(id, props, bsi)
%{"id" => bsi, "default" => true} -> Amethyst.BlockRegistry.add(id, %{}, bsi)
%{"id" => bsi, "properties" => props} -> Amethyst.BlockStates.add(version, id, props, bsi)
%{"id" => bsi, "default" => true} -> Amethyst.BlockStates.add(version, id, %{}, bsi)
end)
end)
:ok
@ -95,15 +95,25 @@ defmodule Amethyst.DataGenerator do
end
end
defp create_blockregistry(version) do
# TODO: unsupervised
Amethyst.BlockStates.start_link(%{}, {:via, Registry, {Amethyst.BlockStateRegistry, version}})
end
@spec generate_and_populate_data(String.t() | :latest, String.t(), String.t(), String.t() | nil) :: :ok | {:error, term}
def generate_and_populate_data(version, jar_path, data_dir, java_bin \\ "java") do
start_time = Time.utc_now()
{:ok, version} = case version do
:latest -> get_latest_version()
version -> {:ok, version}
end
case get_server_jar(version, jar_path) do
{:ok, jar_path} ->
case generate_data_files(jar_path, data_dir, java_bin) do
{:ok, data_path} ->
Logger.info("Finished generating data in #{Time.diff(Time.utc_now(), start_time, :millisecond)}ms")
populate_blockregistry(data_path)
create_blockregistry(version)
populate_blockstates(version, data_path)
Logger.info("Finished generating and populating data in #{Time.diff(Time.utc_now(), start_time, :millisecond)}ms")
{:error, code} -> {:error, code}
end