From 07459e149e9f8a4607634f5881ff1d077d98948e Mon Sep 17 00:00:00 2001 From: Manuel Camejo Date: Thu, 12 Sep 2024 17:00:56 -0300 Subject: [PATCH] bots take a while after attack. allow other skills. (#951) * bots take a while after attack. allow other skills. * format * Fix bots spawn in each game mode * Replace range list of integers to list of strings representing each skill * Pattern match boolean in function signature instead of guard * Delete unused function * Delete unused code --------- Co-authored-by: Nicolas Sanchez --- .../lib/arena/matchmaking/game_launcher.ex | 37 ++----------------- .../lib/arena/matchmaking/quick_game_mode.ex | 11 ++---- apps/bot_manager/lib/bot_state_machine.ex | 20 +++++----- apps/bot_manager/lib/game_socket_handler.ex | 22 +++++++++-- 4 files changed, 35 insertions(+), 55 deletions(-) diff --git a/apps/arena/lib/arena/matchmaking/game_launcher.ex b/apps/arena/lib/arena/matchmaking/game_launcher.ex index 57a1eadd6..3ad1d6221 100644 --- a/apps/arena/lib/arena/matchmaking/game_launcher.ex +++ b/apps/arena/lib/arena/matchmaking/game_launcher.ex @@ -1,26 +1,11 @@ defmodule Arena.Matchmaking.GameLauncher do @moduledoc false alias Arena.Utils - alias Ecto.UUID use GenServer # Time to wait to start game with any amount of clients @start_timeout_ms 4_000 - # The available names for bots to enter a match, we should change this in the future - @bot_names [ - "TheBlackSwordman", - "SlashJava", - "SteelBallRun", - "Jeff", - "Messi", - "Stone Ocean", - "Jeepers Creepers", - "Bob", - "El javo", - "Alberso", - "Thomas" - ] # API def start_link(_) do @@ -96,19 +81,6 @@ defmodule Arena.Matchmaking.GameLauncher do batch_start_at end - defp get_bot_clients(missing_clients) do - characters = - Arena.Configuration.get_game_config() - |> Map.get(:characters) - |> Enum.filter(fn character -> character.active end) - - Enum.map(1..missing_clients//1, fn i -> - client_id = UUID.generate() - - {client_id, Enum.random(characters).name, Enum.at(@bot_names, i), nil} - end) - end - defp spawn_bot_for_player(bot_clients, game_id) do Enum.each(bot_clients, fn {bot_client, _, _, _} -> send(self(), {:spawn_bot_for_player, bot_client, game_id}) @@ -118,12 +90,9 @@ defmodule Arena.Matchmaking.GameLauncher do # Receives a list of clients. # Fills the given list with bots clients, creates a game and tells every client to join that game. defp create_game_for_clients(clients, game_params \\ %{}) do - bot_clients = - if Application.get_env(:arena, :spawn_bots) do - get_bot_clients(Application.get_env(:arena, :players_needed_in_match) - Enum.count(clients)) - else - [] - end + # We won't spawn bots in normal matches. + # Check https://github.com/lambdaclass/mirra_backend/pull/951 to know how to restore former behavior + bot_clients = [] {:ok, game_pid} = GenServer.start(Arena.GameUpdater, %{ diff --git a/apps/arena/lib/arena/matchmaking/quick_game_mode.ex b/apps/arena/lib/arena/matchmaking/quick_game_mode.ex index 879a6d106..82ff88704 100644 --- a/apps/arena/lib/arena/matchmaking/quick_game_mode.ex +++ b/apps/arena/lib/arena/matchmaking/quick_game_mode.ex @@ -42,7 +42,7 @@ defmodule Arena.Matchmaking.QuickGameMode do @impl true def handle_call({:join, client_id, character_name, player_name}, {from_pid, _}, state) do create_game_for_clients([{client_id, character_name, player_name, from_pid}], %{ - bots_enabled: false, + bots_enabled: true, zone_enabled: false }) @@ -88,12 +88,9 @@ defmodule Arena.Matchmaking.QuickGameMode do # Receives a list of clients. # Fills the given list with bots clients, creates a game and tells every client to join that game. defp create_game_for_clients(clients, game_params \\ %{}) do - bot_clients = - if Application.get_env(:arena, :spawn_bots) do - get_bot_clients(Application.get_env(:arena, :players_needed_in_match) - Enum.count(clients)) - else - [] - end + # We will spawn bots in quick-game matches. + # Check https://github.com/lambdaclass/mirra_backend/pull/951 to know how to restore former behavior. + bot_clients = get_bot_clients(Application.get_env(:arena, :players_needed_in_match) - Enum.count(clients)) {:ok, game_pid} = GenServer.start(Arena.GameUpdater, %{ diff --git a/apps/bot_manager/lib/bot_state_machine.ex b/apps/bot_manager/lib/bot_state_machine.ex index cb08224f6..dd4df35eb 100644 --- a/apps/bot_manager/lib/bot_state_machine.ex +++ b/apps/bot_manager/lib/bot_state_machine.ex @@ -10,19 +10,24 @@ defmodule BotManager.BotStateMachine do {:move, %{x: 0, y: 0}} end - def decide_action(%{game_state: game_state, bot_player: bot_player}) do + def decide_action(%{game_state: game_state, bot_player: bot_player, attack_blocked: attack_blocked}) do closest_player = map_directions_to_players(game_state, bot_player) |> Enum.min_by(fn player_info -> player_info.distance end) + random_distance = 1000 + cond do - closest_player.distance > 300 -> + attack_blocked -> + :stand + + closest_player.distance > random_distance -> {:move, closest_player.direction} closest_player.distance < 50 -> - {:move, Vector.mult(closest_player.direction, -1)} + {:move, create_random_direction()} - closest_player.distance <= 300 -> + closest_player.distance <= random_distance -> {:attack, closest_player.direction} true -> @@ -33,12 +38,7 @@ defmodule BotManager.BotStateMachine do 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} - ]) + %{x: Enum.random(1..200) / 100 - 1, y: Enum.random(1..200) / 100 - 1} end defp map_directions_to_players(game_state, bot_player) do diff --git a/apps/bot_manager/lib/game_socket_handler.ex b/apps/bot_manager/lib/game_socket_handler.ex index 9222ecea6..e493cde23 100644 --- a/apps/bot_manager/lib/game_socket_handler.ex +++ b/apps/bot_manager/lib/game_socket_handler.ex @@ -9,7 +9,7 @@ defmodule BotManager.GameSocketHandler do use WebSockex, restart: :temporary require Logger - @decision_delay_ms 200 + @decision_delay_ms 1000 @action_delay_ms 30 def start_link(%{"bot_client" => bot_client, "game_id" => game_id} = params) do @@ -28,7 +28,7 @@ defmodule BotManager.GameSocketHandler do def handle_connect(_conn, state) do send(self(), :decide_action) send(self(), :perform_action) - {:ok, Map.put(state, :bots_enabled?, true)} + {:ok, Map.put(state, :bots_enabled?, true) |> Map.put(:attack_blocked, false)} end def handle_frame({:binary, frame}, state) do @@ -65,11 +65,25 @@ defmodule BotManager.GameSocketHandler do {:ok, Map.put(state, :current_action, action)} end + def handle_info(:unblock_attack, state) do + {:ok, Map.put(state, :attack_blocked, false)} + end + def handle_info(:perform_action, state) do Process.send_after(self(), :perform_action, @action_delay_ms) send_current_action(state) + state = + case state.current_action do + {:attack, _} -> + Map.put(state, :attack_blocked, true) + Process.send_after(self(), :unblock_attack, Enum.random(2000..4000)) + + _ -> + state + end + {:ok, state} end @@ -96,7 +110,7 @@ defmodule BotManager.GameSocketHandler do WebSockex.cast(self(), {:send, {:binary, game_action}}) end - defp send_current_action(%{current_action: {:attack, direction}}) do + defp send_current_action(%{current_action: {:attack, direction}, attack_blocked: false}) do timestamp = DateTime.utc_now() |> DateTime.to_unix(:millisecond) game_action = @@ -104,7 +118,7 @@ defmodule BotManager.GameSocketHandler do action_type: {:attack, %BotManager.Protobuf.Attack{ - skill: "1", + skill: Enum.random(["1", "2", "3"]), parameters: %BotManager.Protobuf.AttackParameters{ target: %BotManager.Protobuf.Direction{ x: direction.x,