From b0f72b35b1af824b84075eb9df2f03abc636097a Mon Sep 17 00:00:00 2001 From: agustinesco Date: Mon, 8 Apr 2024 10:10:59 -0300 Subject: [PATCH 1/8] Start implement bot steering behavior --- apps/bot_manager/lib/game_socket_handler.ex | 146 +++++++++++++++++--- 1 file changed, 123 insertions(+), 23 deletions(-) diff --git a/apps/bot_manager/lib/game_socket_handler.ex b/apps/bot_manager/lib/game_socket_handler.ex index 3c9d5ddee..ee8e13442 100644 --- a/apps/bot_manager/lib/game_socket_handler.ex +++ b/apps/bot_manager/lib/game_socket_handler.ex @@ -8,6 +8,8 @@ defmodule BotManager.GameSocketHandler do require Logger @message_delay_ms 300 + @decision_delay_ms 200 + @action_delay_ms 30 def start_link(%{"bot_client" => bot_client, "game_id" => game_id}) do Logger.info("Connecting bot with client: #{bot_client} to game: #{game_id}") @@ -19,36 +21,56 @@ defmodule BotManager.GameSocketHandler do }) end + ####################### + # handlers # + ####################### + def handle_connect(_conn, state) do - send(self(), :move) - send(self(), :attack) + send(self(), :decide_action) + send(self(), :perfom_action) {:ok, state} end - def handle_frame(_frame, state) do - {:ok, state} + def handle_frame({:binary, frame}, state) do + case BotManager.Protobuf.GameEvent.decode(frame) do + %{event: {:update, game_state}} -> + update_map = %{ + game_state: game_state + } + + {:ok, Map.merge(state, update_map)} + + %{event: {:joined, joined}} -> + {:ok, Map.merge(state, joined)} + + %{event: {:finished, _}} -> + {:stop, state} + + _ -> + {:ok, state} + end end - def handle_info(:move, state) do - timestamp = DateTime.utc_now() |> DateTime.to_unix(:millisecond) - {x, y} = create_random_direction() + def handle_info(:decide_action, %{game_state: game_state} = state) do + Process.send_after(self(), :decide_action, @decision_delay_ms) + players_directions = map_directions_to_players(game_state, state.player_id) |> IO.inspect(label: "aber directions") + state = process_interest_map(state, players_directions) - game_action = - BotManager.Protobuf.GameAction.encode(%BotManager.Protobuf.GameAction{ - action_type: - {:move, - %BotManager.Protobuf.Move{ - direction: %BotManager.Protobuf.Direction{ - x: x, - y: y - } - }}, - timestamp: timestamp - }) + {current_interest, _interest_amount} = + Enum.max_by(state.interest_map, fn {_direction, interest} -> interest end) - WebSockex.cast(self(), {:send, {:binary, game_action}}) + {:ok, Map.put(state, :current_action, {:move, current_interest})} + end + + def handle_info(:decide_action, state) do + Process.send_after(self(), :decide_action, @decision_delay_ms) + {:ok, state} + end - Process.send_after(self(), :move, @message_delay_ms) + def handle_info(:perfom_action, state) do + Process.send_after(self(), :perfom_action, @action_delay_ms) + + send_current_action(state) {:ok, state} end @@ -83,11 +105,35 @@ defmodule BotManager.GameSocketHandler do {:reply, frame, state} end + defp send_current_action(%{current_action: {:move, direction}}) do + timestamp = DateTime.utc_now() |> DateTime.to_unix(:millisecond) + + game_action = + BotManager.Protobuf.GameAction.encode(%BotManager.Protobuf.GameAction{ + action_type: + {:move, + %BotManager.Protobuf.Move{ + direction: %BotManager.Protobuf.Direction{ + x: direction.x, + y: direction.y + } + }}, + timestamp: timestamp + }) + + WebSockex.cast(self(), {:send, {:binary, game_action}}) + end + + defp send_current_action(_), do: nil + def terminate(_, _, _) do - Logger.info("Websocket terminated") - :ok + exit(:normal) end + ####################### + # Helpers # + ####################### + defp ws_url(player_id, game_id) do host = System.get_env("SERVER_HOST", "localhost:4000") @@ -108,4 +154,58 @@ defmodule BotManager.GameSocketHandler do {0, 1} ]) end + + defp process_interest_map(state, players_directions) do + interest_map = + %{ + %{x: 1, y: 0} => 10, + %{x: 0, y: -1} => 10, + %{x: -1, y: 0} => 10, + %{x: 0, y: 1} => 10, + %{x: -1, y: -1} => 10, + %{x: 1, y: -1} => 10, + %{x: -1, y: 1} => 10, + %{x: 1, y: 1} => 10 + } + |> Map.new(fn {vector, _interest} -> + {vector, get_players_interest(vector, players_directions)} + end) + + # Map.merge(interest_map, players_dots, fn _vector, interest, dot -> interest + dot end) + # |> IO.inspect(label: "aber interest with dot") + + Map.put(state, :interest_map, interest_map) + end + + defp map_directions_to_players(game_state, player_id) do + bot_player = Map.get(game_state.players, player_id) + + Map.delete(game_state.players, player_id) + |> Map.new(fn {player_id, player} -> + {player_id, get_ditance_and_direction_to_positions(bot_player.position, player.position)} + end) + end + + defp get_ditance_and_direction_to_positions(base_position, end_position) do + x = end_position.x - base_position.x + y = end_position.y - base_position.y + distance = :math.sqrt(:math.pow(x, 2) + :math.pow(y, 2)) + direction = %{x: x / distance, y: y / distance} + + %{ + direction: direction, + distance: distance + } + end + + defp dot_product(base_vector, position) do + base_vector.x * position.x + base_vector.y * position.y + end + + defp get_players_interest(vector, players_directions) do + Enum.map(players_directions, fn {_player_id, players_information} -> + dot_product(vector, players_information.direction) - players_information.distance + end) + |> Enum.sum() + end end From 8841809ccb4a6cfb22c8165b1457cf0b0d10b484 Mon Sep 17 00:00:00 2001 From: agustinesco Date: Tue, 9 Apr 2024 11:17:40 -0300 Subject: [PATCH 2/8] Regenerate protos --- .../lib/arena/serialization/messages.pb.ex | 2 +- .../serialization/messages.pb.ex | 17 ++++++++++- apps/bot_manager/lib/protobuf/messages.pb.ex | 28 ++++++++++++++++++- .../lib/game_client/protobuf/messages.pb.ex | 2 +- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/apps/arena/lib/arena/serialization/messages.pb.ex b/apps/arena/lib/arena/serialization/messages.pb.ex index 31c82100b..32e3c3735 100644 --- a/apps/arena/lib/arena/serialization/messages.pb.ex +++ b/apps/arena/lib/arena/serialization/messages.pb.ex @@ -244,7 +244,7 @@ end defmodule Arena.Serialization.GameState.ObstaclesEntry do @moduledoc false - use Protobuf, map: true, protoc_gen_elixir_version: "0.12.0", syntax: :proto3 + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" field(:key, 1, type: :uint64) field(:value, 2, type: Arena.Serialization.Entity) diff --git a/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex b/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex index 85c4fc69b..2bc2d1d8d 100644 --- a/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex +++ b/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex @@ -241,6 +241,15 @@ defmodule ArenaLoadTest.Serialization.GameState.ItemsEntry do field(:value, 2, type: ArenaLoadTest.Serialization.Entity) end +defmodule ArenaLoadTest.Serialization.GameState.ObstaclesEntry do + @moduledoc false + + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:key, 1, type: :uint64) + field(:value, 2, type: ArenaLoadTest.Serialization.Entity) +end + defmodule ArenaLoadTest.Serialization.GameState.PoolsEntry do @moduledoc false @@ -310,7 +319,13 @@ defmodule ArenaLoadTest.Serialization.GameState do map: true ) - field(:pools, 14, + field(:obstacles, 14, + repeated: true, + type: ArenaLoadTest.Serialization.GameState.ObstaclesEntry, + map: true + ) + + field(:pools, 15, repeated: true, type: ArenaLoadTest.Serialization.GameState.PoolsEntry, map: true diff --git a/apps/bot_manager/lib/protobuf/messages.pb.ex b/apps/bot_manager/lib/protobuf/messages.pb.ex index 93a19841c..c87c65637 100644 --- a/apps/bot_manager/lib/protobuf/messages.pb.ex +++ b/apps/bot_manager/lib/protobuf/messages.pb.ex @@ -241,6 +241,15 @@ defmodule BotManager.Protobuf.GameState.ItemsEntry do field(:value, 2, type: BotManager.Protobuf.Entity) end +defmodule BotManager.Protobuf.GameState.ObstaclesEntry do + @moduledoc false + + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:key, 1, type: :uint64) + field(:value, 2, type: BotManager.Protobuf.Entity) +end + defmodule BotManager.Protobuf.GameState.PoolsEntry do @moduledoc false @@ -299,7 +308,14 @@ defmodule BotManager.Protobuf.GameState do field(:status, 11, type: BotManager.Protobuf.GameStatus, enum: true) field(:start_game_timestamp, 12, type: :int64, json_name: "startGameTimestamp") field(:items, 13, repeated: true, type: BotManager.Protobuf.GameState.ItemsEntry, map: true) - field(:pools, 14, repeated: true, type: BotManager.Protobuf.GameState.PoolsEntry, map: true) + + field(:obstacles, 14, + repeated: true, + type: BotManager.Protobuf.GameState.ObstaclesEntry, + map: true + ) + + field(:pools, 15, repeated: true, type: BotManager.Protobuf.GameState.PoolsEntry, map: true) end defmodule BotManager.Protobuf.Entity do @@ -337,6 +353,15 @@ defmodule BotManager.Protobuf.Player.EffectsEntry do field(:value, 2, type: BotManager.Protobuf.Effect) end +defmodule BotManager.Protobuf.Player.CooldownsEntry do + @moduledoc false + + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:key, 1, type: :string) + field(:value, 2, type: :uint64) +end + defmodule BotManager.Protobuf.Player do @moduledoc false @@ -359,6 +384,7 @@ defmodule BotManager.Protobuf.Player do field(:power_ups, 9, type: :uint64, json_name: "powerUps") field(:effects, 10, repeated: true, type: BotManager.Protobuf.Player.EffectsEntry, map: true) field(:inventory, 11, type: BotManager.Protobuf.Item) + field(:cooldowns, 12, repeated: true, type: BotManager.Protobuf.Player.CooldownsEntry, map: true) end defmodule BotManager.Protobuf.Effect do diff --git a/apps/game_client/lib/game_client/protobuf/messages.pb.ex b/apps/game_client/lib/game_client/protobuf/messages.pb.ex index 36b174a28..bb0ead8ca 100644 --- a/apps/game_client/lib/game_client/protobuf/messages.pb.ex +++ b/apps/game_client/lib/game_client/protobuf/messages.pb.ex @@ -244,7 +244,7 @@ end defmodule GameClient.Protobuf.GameState.ObstaclesEntry do @moduledoc false - use Protobuf, map: true, protoc_gen_elixir_version: "0.12.0", syntax: :proto3 + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" field(:key, 1, type: :uint64) field(:value, 2, type: GameClient.Protobuf.Entity) From 9d6afed1b52ef26a4326a37805f2621a17e29d50 Mon Sep 17 00:00:00 2001 From: agustinesco Date: Tue, 9 Apr 2024 11:19:43 -0300 Subject: [PATCH 3/8] Replace steering behavior with a simpler one --- apps/bot_manager/lib/bot_state_machine.ex | 62 ++++++++++ apps/bot_manager/lib/game_socket_handler.ex | 129 +++++--------------- apps/bot_manager/lib/math/vector.ex | 19 +++ apps/bot_manager/lib/utils.ex | 5 + 4 files changed, 115 insertions(+), 100 deletions(-) create mode 100644 apps/bot_manager/lib/bot_state_machine.ex create mode 100644 apps/bot_manager/lib/math/vector.ex create mode 100644 apps/bot_manager/lib/utils.ex diff --git a/apps/bot_manager/lib/bot_state_machine.ex b/apps/bot_manager/lib/bot_state_machine.ex new file mode 100644 index 000000000..178bd2f7e --- /dev/null +++ b/apps/bot_manager/lib/bot_state_machine.ex @@ -0,0 +1,62 @@ +defmodule BotManager.BotStateMachine do + @moduledoc """ + This module will take care of deciding what the bot will do on each deciding step + """ + + alias BotManager.Utils + alias BotManager.Math.Vector + + def decide_action(%{game_state: game_state, bot_player: bot_player}) do + closest_player = + map_directions_to_players(game_state, bot_player) + |> Enum.min_by(fn player_info -> player_info.distance end) + + cond do + closest_player.distance > 300 -> + {:move, closest_player.direction} + + closest_player.distance < 50 -> + {:move, Vector.mult(closest_player.direction, -1)} + + closest_player.distance <= 300 -> + {:attack, closest_player.direction} + + true -> + {:move, create_random_direction()} + end + end + + def decide_action(_), do: :stand + + defp create_random_direction() do + Enum.random([ + %{x: 1, y: 0}, + %{x: 0, y: -1}, + %{x: -1, y: 0}, + %{x: 0, y: 1} + ]) + end + + defp map_directions_to_players(game_state, bot_player) do + Map.delete(game_state.players, bot_player.id) + |> Map.filter(fn {_player_id, player} -> Utils.player_alive?(player) end) + |> Enum.map(fn {_player_id, player} -> + player_info = + get_ditance_and_direction_to_positions(bot_player.position, player.position) + + Map.merge(player, player_info) + end) + end + + defp get_ditance_and_direction_to_positions(base_position, end_position) do + x = end_position.x - base_position.x + y = end_position.y - base_position.y + distance = :math.sqrt(:math.pow(x, 2) + :math.pow(y, 2)) + direction = %{x: x / distance, y: y / distance} + + %{ + direction: direction, + distance: distance + } + end +end diff --git a/apps/bot_manager/lib/game_socket_handler.ex b/apps/bot_manager/lib/game_socket_handler.ex index ee8e13442..acd21f94f 100644 --- a/apps/bot_manager/lib/game_socket_handler.ex +++ b/apps/bot_manager/lib/game_socket_handler.ex @@ -4,10 +4,11 @@ defmodule BotManager.GameSocketHandler do It handles the communication with the server. """ + alias BotManager.BotStateMachine + use WebSockex, restart: :transient require Logger - @message_delay_ms 300 @decision_delay_ms 200 @action_delay_ms 30 @@ -34,11 +35,14 @@ defmodule BotManager.GameSocketHandler do def handle_frame({:binary, frame}, state) do case BotManager.Protobuf.GameEvent.decode(frame) do %{event: {:update, game_state}} -> - update_map = %{ + bot_player = Map.get(game_state.players, state.player_id) + + update = %{ + bot_player: bot_player, game_state: game_state } - {:ok, Map.merge(state, update_map)} + {:ok, Map.merge(state, update)} %{event: {:joined, joined}} -> {:ok, Map.merge(state, joined)} @@ -51,20 +55,12 @@ defmodule BotManager.GameSocketHandler do end end - def handle_info(:decide_action, %{game_state: game_state} = state) do + def handle_info(:decide_action, state) do Process.send_after(self(), :decide_action, @decision_delay_ms) - players_directions = map_directions_to_players(game_state, state.player_id) |> IO.inspect(label: "aber directions") - state = process_interest_map(state, players_directions) - {current_interest, _interest_amount} = - Enum.max_by(state.interest_map, fn {_direction, interest} -> interest end) + action = BotStateMachine.decide_action(state) - {:ok, Map.put(state, :current_action, {:move, current_interest})} - end - - def handle_info(:decide_action, state) do - Process.send_after(self(), :decide_action, @decision_delay_ms) - {:ok, state} + {:ok, Map.put(state, :current_action, action)} end def handle_info(:perfom_action, state) do @@ -75,47 +71,43 @@ defmodule BotManager.GameSocketHandler do {:ok, state} end - def handle_info(:attack, state) do + def handle_cast({:send, {_type, _msg} = frame}, state) do + {:reply, frame, state} + end + + defp send_current_action(%{current_action: {:move, direction}}) do timestamp = DateTime.utc_now() |> DateTime.to_unix(:millisecond) - {x, y} = create_random_direction() game_action = BotManager.Protobuf.GameAction.encode(%BotManager.Protobuf.GameAction{ action_type: - {:attack, - %BotManager.Protobuf.Attack{ - skill: "1", - parameters: %BotManager.Protobuf.AttackParameters{ - target: %BotManager.Protobuf.Direction{ - x: x, - y: y - } + {:move, + %BotManager.Protobuf.Move{ + direction: %BotManager.Protobuf.Direction{ + x: direction.x, + y: direction.y } }}, timestamp: timestamp }) WebSockex.cast(self(), {:send, {:binary, game_action}}) - - Process.send_after(self(), :attack, @message_delay_ms) - {:ok, state} - end - - def handle_cast({:send, {_type, _msg} = frame}, state) do - {:reply, frame, state} end - defp send_current_action(%{current_action: {:move, direction}}) do + defp send_current_action(%{current_action: {:attack, direction}}) do timestamp = DateTime.utc_now() |> DateTime.to_unix(:millisecond) game_action = BotManager.Protobuf.GameAction.encode(%BotManager.Protobuf.GameAction{ action_type: - {:move, - %BotManager.Protobuf.Move{ - direction: %BotManager.Protobuf.Direction{ - x: direction.x, - y: direction.y + {:attack, + %BotManager.Protobuf.Attack{ + skill: "1", + parameters: %BotManager.Protobuf.AttackParameters{ + target: %BotManager.Protobuf.Direction{ + x: direction.x, + y: direction.y + } } }}, timestamp: timestamp @@ -145,67 +137,4 @@ defmodule BotManager.GameSocketHandler do "ws://#{host}/play/#{game_id}/#{player_id}" end end - - defp create_random_direction() do - Enum.random([ - {1, 0}, - {0, -1}, - {-1, 0}, - {0, 1} - ]) - end - - defp process_interest_map(state, players_directions) do - interest_map = - %{ - %{x: 1, y: 0} => 10, - %{x: 0, y: -1} => 10, - %{x: -1, y: 0} => 10, - %{x: 0, y: 1} => 10, - %{x: -1, y: -1} => 10, - %{x: 1, y: -1} => 10, - %{x: -1, y: 1} => 10, - %{x: 1, y: 1} => 10 - } - |> Map.new(fn {vector, _interest} -> - {vector, get_players_interest(vector, players_directions)} - end) - - # Map.merge(interest_map, players_dots, fn _vector, interest, dot -> interest + dot end) - # |> IO.inspect(label: "aber interest with dot") - - Map.put(state, :interest_map, interest_map) - end - - defp map_directions_to_players(game_state, player_id) do - bot_player = Map.get(game_state.players, player_id) - - Map.delete(game_state.players, player_id) - |> Map.new(fn {player_id, player} -> - {player_id, get_ditance_and_direction_to_positions(bot_player.position, player.position)} - end) - end - - defp get_ditance_and_direction_to_positions(base_position, end_position) do - x = end_position.x - base_position.x - y = end_position.y - base_position.y - distance = :math.sqrt(:math.pow(x, 2) + :math.pow(y, 2)) - direction = %{x: x / distance, y: y / distance} - - %{ - direction: direction, - distance: distance - } - end - - defp dot_product(base_vector, position) do - base_vector.x * position.x + base_vector.y * position.y - end - - defp get_players_interest(vector, players_directions) do - Enum.map(players_directions, fn {_player_id, players_information} -> - dot_product(vector, players_information.direction) - players_information.distance - end) - |> Enum.sum() - end end diff --git a/apps/bot_manager/lib/math/vector.ex b/apps/bot_manager/lib/math/vector.ex new file mode 100644 index 000000000..01a393f0b --- /dev/null +++ b/apps/bot_manager/lib/math/vector.ex @@ -0,0 +1,19 @@ +defmodule BotManager.Math.Vector do + def sub(vector, value) when is_integer(value) or is_float(value) do + Map.new(vector, fn {_key, vector_value} -> + vector_value - value + end) + end + + def sub(first_vector, second_vector) do + Map.merge(first_vector, second_vector, fn _key, first_vector_value, second_vector_value -> + first_vector_value - second_vector_value + end) + end + + def mult(vector, value) do + Map.new(vector, fn {key, vector_value} -> + {key, vector_value * value} + end) + end +end diff --git a/apps/bot_manager/lib/utils.ex b/apps/bot_manager/lib/utils.ex new file mode 100644 index 000000000..61f091ada --- /dev/null +++ b/apps/bot_manager/lib/utils.ex @@ -0,0 +1,5 @@ +defmodule BotManager.Utils do + def player_alive?(%{aditional_info: {:player, %{health: health}}}), do: health > 0 + + def player_alive?(_), do: :not_a_player +end From cf85eadb2eabc7b008f59ba9883c4f00b5e2ced6 Mon Sep 17 00:00:00 2001 From: agustinesco Date: Tue, 9 Apr 2024 13:42:59 -0300 Subject: [PATCH 4/8] Add moduledoc to missing files --- apps/bot_manager/lib/math/vector.ex | 12 +++++++++++- apps/bot_manager/lib/utils.ex | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/bot_manager/lib/math/vector.ex b/apps/bot_manager/lib/math/vector.ex index 01a393f0b..46c690b3b 100644 --- a/apps/bot_manager/lib/math/vector.ex +++ b/apps/bot_manager/lib/math/vector.ex @@ -1,4 +1,8 @@ defmodule BotManager.Math.Vector do + @moduledoc """ + Module to handle math operations with vectors + """ + def sub(vector, value) when is_integer(value) or is_float(value) do Map.new(vector, fn {_key, vector_value} -> vector_value - value @@ -11,9 +15,15 @@ defmodule BotManager.Math.Vector do end) end - def mult(vector, value) do + def mult(vector, value) when is_integer(value) or is_float(value) do Map.new(vector, fn {key, vector_value} -> {key, vector_value * value} end) end + + def mult(first_vector, second_vector) do + Map.merge(first_vector, second_vector, fn _key, first_vector_value, second_vector_value -> + first_vector_value * second_vector_value + end) + end end diff --git a/apps/bot_manager/lib/utils.ex b/apps/bot_manager/lib/utils.ex index 61f091ada..5e6427fe0 100644 --- a/apps/bot_manager/lib/utils.ex +++ b/apps/bot_manager/lib/utils.ex @@ -1,4 +1,8 @@ defmodule BotManager.Utils do + @moduledoc """ + utils to work with nested game state operations + """ + def player_alive?(%{aditional_info: {:player, %{health: health}}}), do: health > 0 def player_alive?(_), do: :not_a_player From 13b4b1eba57f8368dd51a8e1a2932556e941bd3f Mon Sep 17 00:00:00 2001 From: agustinesco Date: Tue, 9 Apr 2024 14:46:01 -0300 Subject: [PATCH 5/8] Fix vector module --- apps/bot_manager/lib/bot_state_machine.ex | 3 +-- apps/bot_manager/lib/math/vector.ex | 28 +++++++++++++---------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/bot_manager/lib/bot_state_machine.ex b/apps/bot_manager/lib/bot_state_machine.ex index 178bd2f7e..9dec626f8 100644 --- a/apps/bot_manager/lib/bot_state_machine.ex +++ b/apps/bot_manager/lib/bot_state_machine.ex @@ -49,8 +49,7 @@ defmodule BotManager.BotStateMachine do end defp get_ditance_and_direction_to_positions(base_position, end_position) do - x = end_position.x - base_position.x - y = end_position.y - base_position.y + %{x: x, y: y} = Vector.sub(end_position, base_position) distance = :math.sqrt(:math.pow(x, 2) + :math.pow(y, 2)) direction = %{x: x / distance, y: y / distance} diff --git a/apps/bot_manager/lib/math/vector.ex b/apps/bot_manager/lib/math/vector.ex index 46c690b3b..b4e168581 100644 --- a/apps/bot_manager/lib/math/vector.ex +++ b/apps/bot_manager/lib/math/vector.ex @@ -4,26 +4,30 @@ defmodule BotManager.Math.Vector do """ def sub(vector, value) when is_integer(value) or is_float(value) do - Map.new(vector, fn {_key, vector_value} -> - vector_value - value - end) + %{ + x: vector.x - value, + y: vector.y - value + } end def sub(first_vector, second_vector) do - Map.merge(first_vector, second_vector, fn _key, first_vector_value, second_vector_value -> - first_vector_value - second_vector_value - end) + %{ + x: first_vector.x - second_vector.x, + y: first_vector.y - second_vector.y + } end def mult(vector, value) when is_integer(value) or is_float(value) do - Map.new(vector, fn {key, vector_value} -> - {key, vector_value * value} - end) + %{ + x: vector.x * value, + y: vector.y * value + } end def mult(first_vector, second_vector) do - Map.merge(first_vector, second_vector, fn _key, first_vector_value, second_vector_value -> - first_vector_value * second_vector_value - end) + %{ + x: first_vector.x * second_vector.x, + y: first_vector.y * second_vector.y + } end end From 8e01fedb6bcf6d70346214ea00ce124a728ab618 Mon Sep 17 00:00:00 2001 From: agustinesco Date: Thu, 11 Apr 2024 15:08:36 -0300 Subject: [PATCH 6/8] Resotre messages pb file --- apps/arena/lib/arena/serialization/messages.pb.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/arena/lib/arena/serialization/messages.pb.ex b/apps/arena/lib/arena/serialization/messages.pb.ex index 11fe27030..0e91a0fcb 100644 --- a/apps/arena/lib/arena/serialization/messages.pb.ex +++ b/apps/arena/lib/arena/serialization/messages.pb.ex @@ -244,7 +244,7 @@ end defmodule Arena.Serialization.GameState.ObstaclesEntry do @moduledoc false - use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + use Protobuf, map: true, protoc_gen_elixir_version: "0.12.0", syntax: :proto3 field(:key, 1, type: :uint64) field(:value, 2, type: Arena.Serialization.Entity) From 5a0347771c55d29c916bd6ab918fbede65142b2e Mon Sep 17 00:00:00 2001 From: agustinesco Date: Thu, 11 Apr 2024 15:54:27 -0300 Subject: [PATCH 7/8] Regenerate protos --- apps/arena/lib/arena/serialization/messages.pb.ex | 2 +- apps/bot_manager/lib/protobuf/messages.pb.ex | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/arena/lib/arena/serialization/messages.pb.ex b/apps/arena/lib/arena/serialization/messages.pb.ex index 0e91a0fcb..11fe27030 100644 --- a/apps/arena/lib/arena/serialization/messages.pb.ex +++ b/apps/arena/lib/arena/serialization/messages.pb.ex @@ -244,7 +244,7 @@ end defmodule Arena.Serialization.GameState.ObstaclesEntry do @moduledoc false - use Protobuf, map: true, protoc_gen_elixir_version: "0.12.0", syntax: :proto3 + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" field(:key, 1, type: :uint64) field(:value, 2, type: Arena.Serialization.Entity) diff --git a/apps/bot_manager/lib/protobuf/messages.pb.ex b/apps/bot_manager/lib/protobuf/messages.pb.ex index c87c65637..dd99c8a0a 100644 --- a/apps/bot_manager/lib/protobuf/messages.pb.ex +++ b/apps/bot_manager/lib/protobuf/messages.pb.ex @@ -447,6 +447,7 @@ defmodule BotManager.Protobuf.PlayerAction do field(:action, 1, type: BotManager.Protobuf.PlayerActionType, enum: true) field(:duration, 2, type: :uint64) + field(:destination, 3, type: BotManager.Protobuf.Position) end defmodule BotManager.Protobuf.Move do From e4cb6430f1e548f2adab264a6a767b7097ff33f6 Mon Sep 17 00:00:00 2001 From: Agustin Escobar <106101218+agustinesco@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:11:59 -0300 Subject: [PATCH 8/8] Apply suggestions from code review Co-authored-by: Nicolas Continanza --- apps/bot_manager/lib/bot_state_machine.ex | 4 ++-- apps/bot_manager/lib/game_socket_handler.ex | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/bot_manager/lib/bot_state_machine.ex b/apps/bot_manager/lib/bot_state_machine.ex index 9dec626f8..2d05864eb 100644 --- a/apps/bot_manager/lib/bot_state_machine.ex +++ b/apps/bot_manager/lib/bot_state_machine.ex @@ -42,13 +42,13 @@ defmodule BotManager.BotStateMachine do |> Map.filter(fn {_player_id, player} -> Utils.player_alive?(player) end) |> Enum.map(fn {_player_id, player} -> player_info = - get_ditance_and_direction_to_positions(bot_player.position, player.position) + get_distance_and_direction_to_positions(bot_player.position, player.position) Map.merge(player, player_info) end) end - defp get_ditance_and_direction_to_positions(base_position, end_position) do + defp get_distance_and_direction_to_positions(base_position, end_position) do %{x: x, y: y} = Vector.sub(end_position, base_position) distance = :math.sqrt(:math.pow(x, 2) + :math.pow(y, 2)) direction = %{x: x / distance, y: y / distance} diff --git a/apps/bot_manager/lib/game_socket_handler.ex b/apps/bot_manager/lib/game_socket_handler.ex index 9ae42eb29..130a7ec1e 100644 --- a/apps/bot_manager/lib/game_socket_handler.ex +++ b/apps/bot_manager/lib/game_socket_handler.ex @@ -27,7 +27,7 @@ defmodule BotManager.GameSocketHandler do def handle_connect(_conn, state) do send(self(), :decide_action) - send(self(), :perfom_action) + send(self(), :perform_action) {:ok, state} end @@ -62,8 +62,8 @@ defmodule BotManager.GameSocketHandler do {:ok, Map.put(state, :current_action, action)} end - def handle_info(:perfom_action, state) do - Process.send_after(self(), :perfom_action, @action_delay_ms) + def handle_info(:perform_action, state) do + Process.send_after(self(), :perform_action, @action_delay_ms) send_current_action(state)