diff --git a/.gitignore b/.gitignore index 06cd03941..1ae518ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ runtime/ /source_deploy.tar.gz central.tar.gz /bin +.vscode/launch.json # I'm storing server output here, don't want to push it to git example_output diff --git a/lib/teiserver/account/reports/mapping_report.ex b/lib/teiserver/account/reports/mapping_report.ex index 22cd37fd4..ac7f95ace 100644 --- a/lib/teiserver/account/reports/mapping_report.ex +++ b/lib/teiserver/account/reports/mapping_report.ex @@ -27,8 +27,7 @@ defmodule Teiserver.Game.MappingReport do search: [ started_after: start_date |> Timex.to_datetime(), started_before: end_date |> Timex.to_datetime(), - # game_type_in: ["Duel", "Team", "FFA", "Team FFA"], - game_type_in: ["Duel", "Team"], + game_type_in: ["Duel", "Small Team", "Big Team"], of_interest: true, has_winning_team: true ], diff --git a/lib/teiserver/account/reports/open_skill_report.ex b/lib/teiserver/account/reports/open_skill_report.ex index e0fabd2f9..371ee38cd 100644 --- a/lib/teiserver/account/reports/open_skill_report.ex +++ b/lib/teiserver/account/reports/open_skill_report.ex @@ -69,7 +69,7 @@ defmodule Teiserver.Account.OpenSkillReport do defp apply_defaults(params) do Map.merge( %{ - "rating_type" => "Team", + "rating_type" => "Big Team", "metric" => "Game Rating", "last_active" => "7 days", "uncertainty" => "5" diff --git a/lib/teiserver/account/reports/user_age_report.ex b/lib/teiserver/account/reports/user_age_report.ex index 6df260363..ff9bba6eb 100644 --- a/lib/teiserver/account/reports/user_age_report.ex +++ b/lib/teiserver/account/reports/user_age_report.ex @@ -48,7 +48,9 @@ defmodule Teiserver.Account.UserAgeReport do type_where = case params["game_type"] do "Duel" -> "AND m.game_type = 'Duel'" - "Team" -> "AND m.game_type = 'Team'" + "Team" -> "AND m.game_type IN ('Small Team', 'Big Team')" + "Small Team" -> "AND m.game_type = 'Small Team'" + "Big Team" -> "AND m.game_type = 'Big Team'" "FFA" -> "AND m.game_type = 'FFA'" "Raptors" -> "AND m.game_type = 'Raptors'" "Scavengers" -> "AND m.game_type = 'Scavengers'" diff --git a/lib/teiserver/account/tasks/recalculate_user_cache_task.ex b/lib/teiserver/account/tasks/recalculate_user_cache_task.ex index e3e2d1da0..34e912c6f 100644 --- a/lib/teiserver/account/tasks/recalculate_user_cache_task.ex +++ b/lib/teiserver/account/tasks/recalculate_user_cache_task.ex @@ -19,7 +19,8 @@ defmodule Teiserver.Account.RecacheUserStatsTask do case match.game_type do "Duel" -> do_match_processed_duel(userid) "FFA" -> do_match_processed_duel(userid) - "Team" -> do_match_processed_team(userid) + "Small Team" -> do_match_processed_team_small(userid) + "Big Team" -> do_match_processed_team_big(userid) _ -> :ok end @@ -105,8 +106,16 @@ defmodule Teiserver.Account.RecacheUserStatsTask do :ok end - def do_match_processed_team(userid) do - filter_type_id = MatchRatingLib.rating_type_name_lookup()["Team"] + def do_match_processed_team_big(userid) do + do_match_processed_team(userid, "Big Team") + end + + def do_match_processed_team_small(userid) do + do_match_processed_team(userid, "Small Team") + end + + defp do_match_processed_team(userid, team_subtype) do + filter_type_id = MatchRatingLib.rating_type_name_lookup()[team_subtype] logs = Game.list_rating_logs( diff --git a/lib/teiserver/battle/libs/match_lib.ex b/lib/teiserver/battle/libs/match_lib.ex index 9ed533e17..fb7734893 100644 --- a/lib/teiserver/battle/libs/match_lib.ex +++ b/lib/teiserver/battle/libs/match_lib.ex @@ -1,7 +1,7 @@ defmodule Teiserver.Battle.MatchLib do @moduledoc false use TeiserverWeb, :library - alias Teiserver.{Battle, Account} + alias Teiserver.{Config, Battle, Account} alias Teiserver.Battle.{Match, MatchMembership} alias Teiserver.Data.Types, as: T require Logger @@ -12,34 +12,27 @@ defmodule Teiserver.Battle.MatchLib do @spec colours :: atom def colours, do: :success2 - @spec game_type(T.lobby(), map()) :: <<_::24, _::_*8>> - def game_type(lobby, teams) do - bots = Battle.get_bots(lobby.id) + def game_type(team_size, team_count) do + game_type(team_size, team_count, %{}) + end + + def game_type(team_size, team_count, bots) do + max_small_team_size = Config.get_site_config_cache("lobby.Small team game limit") bot_names = bots |> Map.keys() |> Enum.join(" ") - # It is possible for it to be purely bots v bots which will make it appear to be empty teams - # this would cause an error with Enum.max, hence the case statement - max_team_size = - case Enum.map(teams, fn {_, team} -> Enum.count(team) end) do - [] -> - 0 - - counts -> - Enum.max(counts) - end - cond do String.contains?(bot_names, "Scavenger") -> "Scavengers" String.contains?(bot_names, "Chicken") -> "Raptors" String.contains?(bot_names, "Raptor") -> "Raptors" Enum.empty?(bots) == false -> "Bots" - Enum.count(teams) == 2 and max_team_size == 1 -> "Duel" - Enum.count(teams) == 2 -> "Team" - max_team_size == 1 -> "FFA" + team_count == 2 and team_size == 1 -> "Duel" + team_count == 2 and team_size <= max_small_team_size -> "Small Team" + team_count == 2 and team_size > max_small_team_size -> "Big Team" + team_size == 1 -> "FFA" true -> "Team FFA" end end @@ -47,7 +40,8 @@ defmodule Teiserver.Battle.MatchLib do def list_game_types() do [ "Duel", - "Team", + "Small Team", + "Big Team", "FFA", "Team FFA", "Raptors", @@ -59,7 +53,8 @@ defmodule Teiserver.Battle.MatchLib do def list_rated_game_types() do [ "Duel", - "Team", + "Small Team", + "Big Team", "FFA", "Team FFA" ] @@ -85,7 +80,14 @@ defmodule Teiserver.Battle.MatchLib do |> Enum.group_by(fn c -> c.team_number end) if teams != %{} do - the_game_type = game_type(lobby, teams) + team_count = teams |> count + + team_size = + teams + |> Enum.map(fn {_, t} -> t |> count end) + |> Enum.max(fn -> 0 end) + + game_type = game_type(team_size, team_count, bots) match = %{ uuid: match_uuid, @@ -93,10 +95,10 @@ defmodule Teiserver.Battle.MatchLib do map: lobby.map_name, data: nil, tags: modoptions, - team_count: Enum.count(teams), - team_size: Enum.max(Enum.map(teams, fn {_, t} -> Enum.count(t) end)), + team_count: team_count, + team_size: team_size, passworded: lobby.passworded, - game_type: the_game_type, + game_type: game_type, founder_id: lobby.founder_id, bots: bots, queue_id: queue_id, @@ -141,10 +143,17 @@ defmodule Teiserver.Battle.MatchLib do def make_match_name(match) do case match.game_type do - "Duel" -> "Duel on #{match.map}" - "Team" -> "#{match.team_size}v#{match.team_size} on #{match.map}" - "FFA" -> "#{match.team_count} way FFA on #{match.map}" - t -> "#{t} game on #{match.map}" + "Duel" -> + "Duel on #{match.map}" + + type when type in ["Small Team", "Big Team"] -> + "#{match.team_size}v#{match.team_size} on #{match.map}" + + "FFA" -> + "#{match.team_count} way FFA on #{match.map}" + + t -> + "#{t} game on #{match.map}" end end diff --git a/lib/teiserver/battle/schemas/match.ex b/lib/teiserver/battle/schemas/match.ex index 722d9d2fc..a18dfefab 100644 --- a/lib/teiserver/battle/schemas/match.ex +++ b/lib/teiserver/battle/schemas/match.ex @@ -14,7 +14,7 @@ defmodule Teiserver.Battle.Match do field :team_size, :integer field :passworded, :boolean field :processed, :boolean, default: false - # Scavengers, Raptors, Bots, Duel, Team, FFA, Team FFA + # Scavengers, Raptors, Bots, Duel, Small Team, Big Team, FFA, Team FFA field :game_type, :string belongs_to :founder, Teiserver.Account.User diff --git a/lib/teiserver/battle/tasks/breakdown_match_data_task.ex b/lib/teiserver/battle/tasks/breakdown_match_data_task.ex index 2e06c3484..ffb82c1d1 100644 --- a/lib/teiserver/battle/tasks/breakdown_match_data_task.ex +++ b/lib/teiserver/battle/tasks/breakdown_match_data_task.ex @@ -19,7 +19,8 @@ defmodule Teiserver.Battle.Tasks.BreakdownMatchDataTask do %{ duel: get_subset_data(matches, game_type: "Duel"), - team: get_subset_data(matches, game_type: "Team"), + small_team: get_subset_data(matches, game_type: "Small Team"), + big_team: get_subset_data(matches, game_type: "Big Team"), ffa: get_subset_data(matches, game_type: "FFA"), team_ffa: get_subset_data(matches, game_type: "Team FFA"), scavengers: get_subset_data(matches, game_type: "Scavengers"), diff --git a/lib/teiserver/battle/tasks/export_raw_match_metrics_task.ex b/lib/teiserver/battle/tasks/export_raw_match_metrics_task.ex index 8f4a5f63d..59a8b45a3 100644 --- a/lib/teiserver/battle/tasks/export_raw_match_metrics_task.ex +++ b/lib/teiserver/battle/tasks/export_raw_match_metrics_task.ex @@ -31,7 +31,7 @@ defmodule Teiserver.Battle.ExportRawMatchMetricsTask do defp do_output(data, _params) do data |> Stream.filter(fn match -> - match.game_type == "Team" + match.game_type in ["Small Team", "Big Team"] end) |> Stream.map(fn match -> members = diff --git a/lib/teiserver/coordinator/consul_server.ex b/lib/teiserver/coordinator/consul_server.ex index 861ad906c..715050fc8 100644 --- a/lib/teiserver/coordinator/consul_server.ex +++ b/lib/teiserver/coordinator/consul_server.ex @@ -21,7 +21,7 @@ defmodule Teiserver.Coordinator.ConsulServer do alias Teiserver.Lobby.{ChatLib} import Teiserver.Helper.NumberHelper, only: [int_parse: 1] alias Phoenix.PubSub - alias Teiserver.Battle.BalanceLib + alias Teiserver.Battle.{BalanceLib, MatchLib} alias Teiserver.Data.Types, as: T alias Teiserver.Coordinator.{ConsulCommands, CoordinatorLib, SpadsParser} @@ -835,9 +835,10 @@ defmodule Teiserver.Coordinator.ConsulServer do @spec user_allowed_to_play?(T.user(), T.client(), map()) :: boolean() defp user_allowed_to_play?(user, client, state) do player_list = list_players(state) + rating_type = MatchLib.game_type(state.host_teamsize, state.host_teamcount) {player_rating, player_uncertainty} = - BalanceLib.get_user_rating_value_uncertainty_pair(user.id, "Team") + BalanceLib.get_user_rating_value_uncertainty_pair(user.id, rating_type) player_rating = max(player_rating, 1) avoid_status = Account.check_avoid_status(user.id, player_list) diff --git a/lib/teiserver/game/libs/match_rating_lib.ex b/lib/teiserver/game/libs/match_rating_lib.ex index afc34c41d..91f63dc65 100644 --- a/lib/teiserver/game/libs/match_rating_lib.ex +++ b/lib/teiserver/game/libs/match_rating_lib.ex @@ -10,7 +10,8 @@ defmodule Teiserver.Game.MatchRatingLib do alias Teiserver.Battle.{BalanceLib, MatchLib} require Logger - @rated_match_types ["Team", "Duel", "FFA", "Team FFA", "Partied Team"] + @rated_match_types ["Small Team", "Big Team", "Duel", "Team", "FFA", "Team FFA", "Partied Team"] + # TODO Remove "Team" from here once the split is done @spec rating_type_list() :: [String.t()] def rating_type_list() do @@ -192,7 +193,7 @@ defmodule Teiserver.Game.MatchRatingLib do rate_result = rate_with_ids([winner_ratings, loser_ratings], as_map: true) status_lookup = - if match.game_type == "Team" do + if match.game_type in ["Small Team", "Big Team"] do match.members |> Map.new(fn membership -> {membership.user_id, @@ -358,7 +359,7 @@ defmodule Teiserver.Game.MatchRatingLib do win_result = Map.new(win_result) status_lookup = - if Enum.member?(["Team", "Team FFA"], match.game_type) do + if Enum.member?(["Small Team", "Big Team", "Team FFA"], match.game_type) do match.members |> Map.new(fn membership -> {membership.user_id, @@ -772,7 +773,6 @@ defmodule Teiserver.Game.MatchRatingLib do results = Battle.list_matches( search: [ - # game_type_in: ["Team"], game_type_in: @rated_match_types, processed: true, started_after: Timex.now() |> Timex.shift(days: -31) diff --git a/lib/teiserver/game/servers/balancer_server.ex b/lib/teiserver/game/servers/balancer_server.ex index fa72d846f..c35913e15 100644 --- a/lib/teiserver/game/servers/balancer_server.ex +++ b/lib/teiserver/game/servers/balancer_server.ex @@ -4,6 +4,7 @@ defmodule Teiserver.Game.BalancerServer do alias Teiserver.Data.Types, as: T alias Teiserver.Battle.BalanceLib alias Teiserver.{Battle, Coordinator} + alias Teiserver.Battle.MatchLib @tick_interval 2_000 @@ -161,28 +162,25 @@ defmodule Teiserver.Game.BalancerServer do @spec do_make_balance(non_neg_integer(), [T.client()], List.t()) :: map() defp do_make_balance(team_count, players, opts) do - player_count = Enum.count(players) - - rating_type = - cond do - player_count == 2 -> - "Duel" + teams = + players + |> Enum.group_by(fn c -> c.team_number end) - team_count > 2 -> - if player_count > team_count, do: "Team", else: "FFA" + team_size = + teams + |> Enum.map(fn {_, t} -> Enum.count(t) end) + |> Enum.max(fn -> 0 end) - true -> - "Team" - end + game_type = MatchLib.game_type(team_size, team_count) if opts[:allow_groups] do - party_result = make_grouped_balance(team_count, players, rating_type, opts) + party_result = make_grouped_balance(team_count, players, game_type, opts) if party_result.deviation > opts[:max_deviation] do make_solo_balance( team_count, players, - rating_type, + game_type, [ "Tried grouped mode, got a deviation of #{party_result.deviation} and reverted to solo mode" ], @@ -192,12 +190,12 @@ defmodule Teiserver.Game.BalancerServer do party_result end else - make_solo_balance(team_count, players, rating_type, [], opts) + make_solo_balance(team_count, players, game_type, [], opts) end end @spec make_grouped_balance(non_neg_integer(), [T.client()], String.t(), list()) :: map() - defp make_grouped_balance(team_count, players, rating_type, opts) do + defp make_grouped_balance(team_count, players, game_type, opts) do # Group players into parties partied_players = players @@ -212,15 +210,14 @@ defmodule Teiserver.Game.BalancerServer do player_id_list |> Enum.map(fn userid -> %{ - userid => - BalanceLib.get_user_rating_rank(userid, rating_type, opts[:fuzz_multiplier]) + userid => BalanceLib.get_user_rating_rank(userid, game_type, opts[:fuzz_multiplier]) } end) {_party_id, player_id_list} -> player_id_list |> Map.new(fn userid -> - {userid, BalanceLib.get_user_rating_rank(userid, rating_type, opts[:fuzz_multiplier])} + {userid, BalanceLib.get_user_rating_rank(userid, game_type, opts[:fuzz_multiplier])} end) end) |> List.flatten() @@ -231,12 +228,12 @@ defmodule Teiserver.Game.BalancerServer do @spec make_solo_balance(non_neg_integer(), [T.client()], String.t(), [String.t()], list()) :: map() - defp make_solo_balance(team_count, players, rating_type, initial_logs, opts) do + defp make_solo_balance(team_count, players, game_type, initial_logs, opts) do groups = players |> Enum.map(fn %{userid: userid} -> %{ - userid => BalanceLib.get_user_rating_rank(userid, rating_type, opts[:fuzz_multiplier]) + userid => BalanceLib.get_user_rating_rank(userid, game_type, opts[:fuzz_multiplier]) } end) diff --git a/lib/teiserver/libs/teiserver_configs.ex b/lib/teiserver/libs/teiserver_configs.ex index 44f5e1884..27024b286 100644 --- a/lib/teiserver/libs/teiserver_configs.ex +++ b/lib/teiserver/libs/teiserver_configs.ex @@ -411,6 +411,15 @@ defmodule Teiserver.TeiserverConfigs do "The percentage of players who would need to avoid someone to prevent them becoming a player", default: 50 }) + + add_site_config_type(%{ + key: "lobby.Small team game limit", + section: "Lobbies", + type: "integer", + permissions: ["Admin"], + description: "Maximum team size to be considered as a small team game", + default: 5 + }) end defp discord_configs() do diff --git a/lib/teiserver/libs/test_lib.ex b/lib/teiserver/libs/test_lib.ex index c75eb2f78..de170a19b 100644 --- a/lib/teiserver/libs/test_lib.ex +++ b/lib/teiserver/libs/test_lib.ex @@ -1,7 +1,6 @@ defmodule Teiserver.TeiserverTestLib do @moduledoc false alias Teiserver.{Client, CacheUser, Account} - alias Teiserver.Lobby.LobbyLib alias Teiserver.Account.AccoladeLib alias Teiserver.Protocols.TachyonLib alias Teiserver.Coordinator.CoordinatorServer @@ -622,7 +621,8 @@ defmodule Teiserver.TeiserverTestLib do Teiserver.Account.get_or_add_smurf_key_type("hw3") Teiserver.Game.get_or_add_rating_type("Duel") - Teiserver.Game.get_or_add_rating_type("Team") + Teiserver.Game.get_or_add_rating_type("Small Team") + Teiserver.Game.get_or_add_rating_type("Big Team") Teiserver.Game.get_or_add_rating_type("FFA") Teiserver.Telemetry.get_or_add_complex_server_event_type("Server startup") diff --git a/lib/teiserver/logging/tasks/match_graph_logs_task.ex b/lib/teiserver/logging/tasks/match_graph_logs_task.ex index eead41702..8fa33882f 100644 --- a/lib/teiserver/logging/tasks/match_graph_logs_task.ex +++ b/lib/teiserver/logging/tasks/match_graph_logs_task.ex @@ -5,7 +5,8 @@ defmodule Teiserver.Logging.MatchGraphLogsTask do def perform(logs, "split", key) do [ {"Duel", "duel.aggregate.#{key}"}, - {"Team", "team.aggregate.#{key}"}, + {"Small Team", "team.aggregate.#{key}"}, + {"Big Team", "team.aggregate.#{key}"}, {"FFA", "ffa.aggregate.#{key}"}, {"Team FFA", "team_ffa.aggregate.#{key}"}, {"Bot", "bots.aggregate.#{key}"}, @@ -34,7 +35,8 @@ defmodule Teiserver.Logging.MatchGraphLogsTask do pvp = Map.get(l.data["duel"]["aggregate"], key, 0) + Map.get(l.data["ffa"]["aggregate"], key, 0) + - Map.get(l.data["team"]["aggregate"], key, 0) + + Map.get(l.data["small_team"]["aggregate"], key, 0) + + Map.get(l.data["big_team"]["aggregate"], key, 0) + Map.get(l.data["team_ffa"]["aggregate"], key, 0) pve = @@ -84,7 +86,8 @@ defmodule Teiserver.Logging.MatchGraphLogsTask do pvp = Map.get(l.data["duel"]["aggregate"], key, 0) + Map.get(l.data["ffa"]["aggregate"], key, 0) + - Map.get(l.data["team"]["aggregate"], key, 0) + Map.get(l.data["big_team"]["aggregate"], key, 0) + + Map.get(l.data["team_ffa"]["aggregate"], key, 0) coop = Map.get(l.data["raptors"]["aggregate"], key, 0) + diff --git a/lib/teiserver/logging/tasks/persist_server_day_task.ex b/lib/teiserver/logging/tasks/persist_server_day_task.ex index d14cd8a96..18a8a337e 100644 --- a/lib/teiserver/logging/tasks/persist_server_day_task.ex +++ b/lib/teiserver/logging/tasks/persist_server_day_task.ex @@ -562,7 +562,8 @@ defmodule Teiserver.Logging.Tasks.PersistServerDayTask do "Raptors" -> :raptors "Bots" -> :bots "Duel" -> :duel - "Team" -> :team + "Small Team" -> :small_team + "Big Team" -> :big_team "FFA" -> :ffa "Team FFA" -> :team_ffa end diff --git a/lib/teiserver/mix_tasks/fake_data.ex b/lib/teiserver/mix_tasks/fake_data.ex index 6fd69d24f..1b322b40b 100644 --- a/lib/teiserver/mix_tasks/fake_data.ex +++ b/lib/teiserver/mix_tasks/fake_data.ex @@ -7,6 +7,7 @@ defmodule Mix.Tasks.Teiserver.Fakedata do alias Teiserver.{Account, Logging, Battle, Moderation} alias Teiserver.Helper.StylingHelper + alias Teiserver.Battle.MatchLib require Logger @settings %{ @@ -333,6 +334,8 @@ defmodule Mix.Tasks.Teiserver.Fakedata do team1 = shuffled_users |> Enum.take(team_size) team2 = shuffled_users |> Enum.reverse() |> Enum.take(team_size) + game_type = MatchLib.game_type(team_size, 2) + team1_score = team1 |> Enum.map(fn {_, name} -> String.length(name) end) @@ -358,7 +361,7 @@ defmodule Mix.Tasks.Teiserver.Fakedata do team_size: team_size, passworded: false, processed: true, - game_type: if(team_size == 1, do: "Duel", else: "Team"), + game_type: game_type, # All rooms are hosted by the same user for now founder_id: 1, diff --git a/lib/teiserver_web/controllers/admin/match_controller.ex b/lib/teiserver_web/controllers/admin/match_controller.ex index 633539ac3..7da660709 100644 --- a/lib/teiserver_web/controllers/admin/match_controller.ex +++ b/lib/teiserver_web/controllers/admin/match_controller.ex @@ -231,17 +231,7 @@ defmodule TeiserverWeb.Admin.MatchController do end defp generate_new_balance_data(match) do - rating_type = - cond do - match.team_size == 1 -> - "Duel" - - match.team_count > 2 -> - if match.team_size > 1, do: "Team FFA", else: "FFA" - - true -> - "Team" - end + rating_type = MatchLib.game_type(match.team_size, match.team_count) partied_players = match.members diff --git a/lib/teiserver_web/controllers/api/spads_controller.ex b/lib/teiserver_web/controllers/api/spads_controller.ex index ace9e1b20..b7433c77e 100644 --- a/lib/teiserver_web/controllers/api/spads_controller.ex +++ b/lib/teiserver_web/controllers/api/spads_controller.ex @@ -2,7 +2,7 @@ defmodule TeiserverWeb.API.SpadsController do use TeiserverWeb, :controller alias Teiserver.Config alias Teiserver.{Account, Coordinator, Battle} - alias Teiserver.Battle.BalanceLib + alias Teiserver.Battle.{BalanceLib, MatchLib} import Teiserver.Helper.NumberHelper, only: [int_parse: 1] require Logger @@ -20,15 +20,23 @@ defmodule TeiserverWeb.API.SpadsController do "target_id" => target_id_str, "type" => type }) do + target_id = int_parse(target_id_str) + lobby = get_member_lobby(target_id) + + host_ip = + case lobby do + nil -> nil + _ -> Account.get_client_by_id(lobby.founder_id).ip + end + actual_type = case type do - "TeamFFA" -> "Team" + "Team" -> get_team_subtype(lobby) + # Team FFA uses Big Team rating + "TeamFFA" -> "Big Team" v -> v end - target_id = int_parse(target_id_str) - host_ip = get_member_of_lobby_host_ip(target_id) - conn_ip = conn |> Teiserver.Logging.LoggingPlug.get_ip_from_conn() @@ -147,23 +155,17 @@ defmodule TeiserverWeb.API.SpadsController do if balance_result do # Get some counts for later - total_players = - balance_result.team_sizes - |> Map.values() - |> Enum.sum() - team_count = balance_result.team_sizes |> Enum.count() - # Calculate the rating type - rating_type = - cond do - total_players == 2 -> "Duel" - team_count == 2 -> "Team" - total_players == team_count -> "FFA" - true -> "Team FFA" - end + team_size = + balance_result.team_sizes + |> Map.values() + |> Enum.max() + + # Get the rating type + rating_type = MatchLib.game_type(team_size, team_count) # Temporary solution until Team FFA ratings are fixed rating_type = @@ -214,28 +216,42 @@ defmodule TeiserverWeb.API.SpadsController do end end - def get_member_of_lobby_host_ip(nil), do: nil + defp get_member_lobby(nil), do: nil - def get_member_of_lobby_host_ip(userid) do + @spec get_member_lobby(non_neg_integer()) :: T.lobby() | nil + defp get_member_lobby(userid) do case Account.get_client_by_id(userid) do nil -> nil client -> - get_lobby_host_ip(client.lobby_id) + Battle.get_lobby(client.lobby_id) end end - def get_lobby_host_ip(nil), do: nil + defp get_team_subtype(nil), do: "Big Team" - def get_lobby_host_ip(lobby_id) do - case Battle.get_lobby(lobby_id) do - nil -> - nil + defp get_team_subtype(lobby) do + max_small_team_size = Config.get_site_config_cache("lobby.Small team game limit") - lobby -> - host = Account.get_client_by_id(lobby.founder_id) - host.ip + teams = + lobby.players + |> Account.list_clients() + |> Enum.filter(fn c -> c.player == true end) + |> Enum.group_by(fn c -> c.team_number end) + + max_team_size = + case Enum.map(teams, fn {_, team} -> Enum.count(team) end) do + [] -> + 0 + + counts -> + Enum.max(counts) + end + + cond do + Enum.count(teams) == 2 and max_team_size <= max_small_team_size -> "Small Team" + true -> "Big Team" end end end diff --git a/lib/teiserver_web/controllers/report/rating_controller.ex b/lib/teiserver_web/controllers/report/rating_controller.ex index 873adce78..ec5ad4183 100644 --- a/lib/teiserver_web/controllers/report/rating_controller.ex +++ b/lib/teiserver_web/controllers/report/rating_controller.ex @@ -13,8 +13,8 @@ defmodule TeiserverWeb.Report.RatingController do action: {Phoenix.Controller, :action_name}, user: {Teiserver.Account.AuthLib, :current_user} - plug(:add_breadcrumb, name: 'Reports', url: '/teiserver/reports') - plug(:add_breadcrumb, name: 'Reports', url: '/teiserver/reports/ratings') + plug(:add_breadcrumb, name: ~c"Reports", url: ~c"/teiserver/reports") + plug(:add_breadcrumb, name: ~c"Reports", url: ~c"/teiserver/reports/ratings") @spec distribution_table(Plug.Conn.t(), map) :: Plug.Conn.t() def distribution_table(conn, _params) do @@ -55,7 +55,8 @@ defmodule TeiserverWeb.Report.RatingController do rating_type = cond do Enum.count(player_ids) == 2 -> "Duel" - true -> "Team" + # TODO Should probably get rating based on team size instad + true -> "Big Team" end rating_lookup = diff --git a/lib/teiserver_web/live/moderation/report_user/index.ex b/lib/teiserver_web/live/moderation/report_user/index.ex index 14fc43f17..c3d32ff6c 100644 --- a/lib/teiserver_web/live/moderation/report_user/index.ex +++ b/lib/teiserver_web/live/moderation/report_user/index.ex @@ -191,9 +191,14 @@ defmodule TeiserverWeb.Moderation.ReportUserLive.Index do |> Enum.map(fn match -> label = case match.game_type do - "Team" -> "#{match.team_size} vs #{match.team_size} on #{match.map}" - "FFA" -> "#{match.team_count} way FFA on #{match.map}" - v -> v + type when type in ["Small Team", "Big Team"] -> + "#{match.team_size} vs #{match.team_size} on #{match.map}" + + "FFA" -> + "#{match.team_count} way FFA on #{match.map}" + + v -> + v end time_ago = diff --git a/lib/teiserver_web/templates/admin/match/search.html.heex b/lib/teiserver_web/templates/admin/match/search.html.heex index e2d9672bb..504bb8c52 100644 --- a/lib/teiserver_web/templates/admin/match/search.html.heex +++ b/lib/teiserver_web/templates/admin/match/search.html.heex @@ -78,7 +78,18 @@ enumerable: [ %{id: "", name: "Any", icon: "fa-solid fa-square", colour: "#AA0000"}, %{id: "Duel", name: "Duel", icon: "fa-solid fa-square", colour: "#AA0000"}, - %{id: "Team", name: "Team", icon: "fa-solid fa-square", colour: "#AA0000"}, + %{ + id: "Small Team", + name: "Small Team", + icon: "fa-solid fa-square", + colour: "#AA0000" + }, + %{ + id: "Big Team", + name: "Big Team", + icon: "fa-solid fa-square", + colour: "#AA0000" + }, %{id: "FFA", name: "FFA", icon: "fa-solid fa-square", colour: "#AA0000"}, %{ id: "Team FFA", diff --git a/lib/teiserver_web/templates/admin/user/ratings.html.heex b/lib/teiserver_web/templates/admin/user/ratings.html.heex index a95fa34b2..0816942b5 100644 --- a/lib/teiserver_web/templates/admin/user/ratings.html.heex +++ b/lib/teiserver_web/templates/admin/user/ratings.html.heex @@ -99,7 +99,7 @@ Game - <%= if @filter == "Team" do %> + <%= if @filter in ["Small Team", "Big Team"] do %> Play <% end %> Players @@ -122,7 +122,7 @@ end {exit_status, play_percentage} = - if log.match.game_type == "Team" do + if log.match.game_type in ["Small Team", "Big Team"] do exit_status = Teiserver.Battle.MatchLib.calculate_exit_status( log.match_membership.left_after, @@ -142,7 +142,7 @@ <%= if log.match do %> <%= log.match.map %> - <%= if @filter == "Team" do %> + <%= if @filter in ["Small Team", "Big Team"] do %> <%= case exit_status do %> <% :stayed -> %> diff --git a/lib/teiserver_web/templates/report/report/open_skill.html.heex b/lib/teiserver_web/templates/report/report/open_skill.html.heex index 5f617a269..df5d97012 100644 --- a/lib/teiserver_web/templates/report/report/open_skill.html.heex +++ b/lib/teiserver_web/templates/report/report/open_skill.html.heex @@ -58,7 +58,8 @@ :report, :rating_type, [ - "Team", + "Small Team", + "Big Team", "Partied Team", "Duel", "FFA", diff --git a/lib/teiserver_web/templates/report/report/user_age.html.heex b/lib/teiserver_web/templates/report/report/user_age.html.heex index b8de1c1ca..d78020af9 100644 --- a/lib/teiserver_web/templates/report/report/user_age.html.heex +++ b/lib/teiserver_web/templates/report/report/user_age.html.heex @@ -74,7 +74,8 @@ [ "Any", "Duel", - "Team", + "Small Team", + "Big Team", "FFA", "Raptors", "Scavengers", diff --git a/test/teiserver/account/accolade_bot_test.exs b/test/teiserver/account/accolade_bot_test.exs index 94bca8f5e..e1c28f77f 100644 --- a/test/teiserver/account/accolade_bot_test.exs +++ b/test/teiserver/account/accolade_bot_test.exs @@ -29,7 +29,7 @@ defmodule Teiserver.Account.AccoladeBotTest do team_count: 2, team_size: 2, passworded: false, - game_type: "Team", + game_type: "Small Team", founder_id: host.id, founder_name: host.name, server_uuid: "123", diff --git a/test/teiserver/coordinator/consul_commands_test.exs b/test/teiserver/coordinator/consul_commands_test.exs index 48bee636a..b367de54e 100644 --- a/test/teiserver/coordinator/consul_commands_test.exs +++ b/test/teiserver/coordinator/consul_commands_test.exs @@ -456,13 +456,13 @@ defmodule Teiserver.Coordinator.ConsulCommandsTest do # Minimum assert Coordinator.call_consul(lobby_id, {:get, :minimum_rating_to_play}) == 0 - data = %{cmd: "c.lobby.message", message: "$minplaylevel 3"} + data = %{cmd: "c.lobby.message", message: "$minratinglevel 3"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :minimum_rating_to_play}) == 3 - data = %{cmd: "c.lobby.message", message: "$minplaylevel Xy"} + data = %{cmd: "c.lobby.message", message: "$minratinglevel Xy"} _tachyon_send(hsocket, data) :timer.sleep(500) @@ -471,52 +471,52 @@ defmodule Teiserver.Coordinator.ConsulCommandsTest do # Maximum assert Coordinator.call_consul(lobby_id, {:get, :maximum_rating_to_play}) == 1000 - data = %{cmd: "c.lobby.message", message: "$maxplaylevel 13"} + data = %{cmd: "c.lobby.message", message: "$maxratinglevel 13"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :maximum_rating_to_play}) == 13 - data = %{cmd: "c.lobby.message", message: "$maxplaylevel Xy"} + data = %{cmd: "c.lobby.message", message: "$maxratinglevel Xy"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :maximum_rating_to_play}) == 13 # Now try to set each the other side of the other - data = %{cmd: "c.lobby.message", message: "$maxplaylevel 1"} + data = %{cmd: "c.lobby.message", message: "$maxratinglevel 1"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :maximum_rating_to_play}) == 4 - data = %{cmd: "c.lobby.message", message: "$maxplaylevel 16"} + data = %{cmd: "c.lobby.message", message: "$maxratinglevel 16"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :maximum_rating_to_play}) == 16 - data = %{cmd: "c.lobby.message", message: "$minplaylevel 20"} + data = %{cmd: "c.lobby.message", message: "$minratinglevel 20"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :minimum_rating_to_play}) == 15 - data = %{cmd: "c.lobby.message", message: "$setplaylevels 7 9"} + data = %{cmd: "c.lobby.message", message: "$setratinglevels 7 9"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :minimum_rating_to_play}) == 7 assert Coordinator.call_consul(lobby_id, {:get, :maximum_rating_to_play}) == 9 - data = %{cmd: "c.lobby.message", message: "$setplaylevels 50 33"} + data = %{cmd: "c.lobby.message", message: "$setratinglevels 50 33"} _tachyon_send(hsocket, data) :timer.sleep(500) assert Coordinator.call_consul(lobby_id, {:get, :minimum_rating_to_play}) == 33 assert Coordinator.call_consul(lobby_id, {:get, :maximum_rating_to_play}) == 50 - data = %{cmd: "c.lobby.message", message: "$resetplaylevels"} + data = %{cmd: "c.lobby.message", message: "$resetratinglevels"} _tachyon_send(hsocket, data) :timer.sleep(500) diff --git a/test/teiserver/coordinator/coordinator_commands_test.exs b/test/teiserver/coordinator/coordinator_commands_test.exs index eb5667a17..c8f79fd0a 100644 --- a/test/teiserver/coordinator/coordinator_commands_test.exs +++ b/test/teiserver/coordinator/coordinator_commands_test.exs @@ -1,6 +1,6 @@ defmodule Teiserver.Coordinator.CoordinatorCommandsTest do use Teiserver.ServerCase, async: false - alias Teiserver.{User, Coordinator, Account} + alias Teiserver.{CacheUser, Coordinator, Account} import Teiserver.TeiserverTestLib, only: [tachyon_auth_setup: 0, _tachyon_send: 2, _tachyon_recv: 1, new_user: 0] @@ -44,7 +44,7 @@ defmodule Teiserver.Coordinator.CoordinatorCommandsTest do assert String.contains?(message, "$whoami") # Moderator help test - User.update_user(%{user | moderator: true}) + CacheUser.update_user(%{user | moderator: true}) message_coordinator(socket, "$help") [reply] = _tachyon_recv(socket) assert reply == %{"cmd" => "s.communication.send_direct_message", "result" => "success"} @@ -94,7 +94,7 @@ defmodule Teiserver.Coordinator.CoordinatorCommandsTest do refute String.contains?(message, "Displays this help text.") # Moderator pull test - User.update_user(%{user | moderator: true}) + CacheUser.update_user(%{user | moderator: true}) message_coordinator(socket, "$help pull") [reply] = _tachyon_recv(socket) assert reply == %{"cmd" => "s.communication.send_direct_message", "result" => "success"} @@ -195,7 +195,7 @@ defmodule Teiserver.Coordinator.CoordinatorCommandsTest do "sender_id" => coordinator_userid } - user = User.get_user_by_id(user.id) + user = CacheUser.get_user_by_id(user.id) assert user.ignored == [user2.id] # Now use it again, make sure we don't get a crash @@ -211,7 +211,7 @@ defmodule Teiserver.Coordinator.CoordinatorCommandsTest do "sender_id" => coordinator_userid } - user = User.get_user_by_id(user.id) + user = CacheUser.get_user_by_id(user.id) assert user.ignored == [] # Now unmute again @@ -227,7 +227,7 @@ defmodule Teiserver.Coordinator.CoordinatorCommandsTest do "sender_id" => coordinator_userid } - user = User.get_user_by_id(user.id) + user = CacheUser.get_user_by_id(user.id) assert user.ignored == [] end diff --git a/test/teiserver/coordinator/match_monitor_server_test.exs b/test/teiserver/coordinator/match_monitor_server_test.exs index 6bb8225ee..34bee7a12 100644 --- a/test/teiserver/coordinator/match_monitor_server_test.exs +++ b/test/teiserver/coordinator/match_monitor_server_test.exs @@ -1,6 +1,6 @@ defmodule Teiserver.Coordinator.MatchMonitorServerTest do use Teiserver.ServerCase, async: false - alias Teiserver.{User, Chat, Client, Lobby} + alias Teiserver.{CacheUser, Chat, Client, Lobby} alias Teiserver.Coordinator.{CoordinatorServer} import Teiserver.TeiserverTestLib, @@ -13,7 +13,7 @@ defmodule Teiserver.Coordinator.MatchMonitorServerTest do Teiserver.Battle.start_match_monitor() %{socket: hsocket, user: host} = tachyon_auth_setup() %{socket: psocket, user: player} = tachyon_auth_setup() - User.update_user(%{host | bot: true}) + CacheUser.update_user(%{host | bot: true}) battle_data = %{ cmd: "c.lobby.create", @@ -56,7 +56,7 @@ defmodule Teiserver.Coordinator.MatchMonitorServerTest do end test "chat messages", %{hsocket: hsocket, host: host, player: player} do - monitor_user = User.get_user_by_name("AutohostMonitor") + monitor_user = CacheUser.get_user_by_name("AutohostMonitor") messages1 = Chat.list_lobby_messages(search: [user_id: host.id]) messages2 = Chat.list_lobby_messages(search: [user_id: player.id]) diff --git a/test/teiserver/coordinator/memes_test.exs b/test/teiserver/coordinator/memes_test.exs index 2feb8aa68..43a6e6b10 100644 --- a/test/teiserver/coordinator/memes_test.exs +++ b/test/teiserver/coordinator/memes_test.exs @@ -1,7 +1,7 @@ defmodule Teiserver.Coordinator.MemesTest do use Teiserver.ServerCase, async: false alias Teiserver.Account.ClientLib - alias Teiserver.{User, Client, Coordinator, Lobby} + alias Teiserver.{CacheUser, Client, Coordinator, Lobby} require Logger import Teiserver.TeiserverTestLib, @@ -13,7 +13,7 @@ defmodule Teiserver.Coordinator.MemesTest do %{socket: psocket, user: player} = tachyon_auth_setup() # User needs to be a moderator (at this time) to start/stop Coordinator mode - User.update_user(%{host | moderator: true}) + CacheUser.update_user(%{host | moderator: true}) ClientLib.refresh_client(host.id) lobby_data = %{ @@ -102,7 +102,7 @@ defmodule Teiserver.Coordinator.MemesTest do "cmd" => "s.lobby.set_modoptions", "lobby_id" => lobby_id, "new_options" => %{ - "game/modoptions/resourceincomemultiplier" => "0" + "game/modoptions/multiplier_resourceincome" => "0" } } end @@ -115,7 +115,7 @@ defmodule Teiserver.Coordinator.MemesTest do "cmd" => "s.lobby.set_modoptions", "lobby_id" => lobby_id, "new_options" => %{ - "game/modoptions/resourceincomemultiplier" => "1000", + "game/modoptions/multiplier_resourceincome" => "1000", "game/modoptions/startenergy" => "100000000", "game/modoptions/startmetal" => "100000000" } diff --git a/test/teiserver/coordinator/moderation_test.exs b/test/teiserver/coordinator/moderation_test.exs index 738ba88a6..64b2d0aee 100644 --- a/test/teiserver/coordinator/moderation_test.exs +++ b/test/teiserver/coordinator/moderation_test.exs @@ -1,6 +1,6 @@ defmodule Teiserver.Coordinator.ModerationTest do use Teiserver.ServerCase, async: false - alias Teiserver.{User, Coordinator, Client, Moderation} + alias Teiserver.{CacheUser, Coordinator, Client, Moderation} import Teiserver.Helper.TimexHelper, only: [date_to_str: 2] alias Teiserver.Moderation.RefreshUserRestrictionsTask @@ -16,9 +16,9 @@ defmodule Teiserver.Coordinator.ModerationTest do test "login with warning", %{user: user} do delay = Teiserver.Config.get_site_config_cache("teiserver.Post login action delay") - refute User.has_warning?(user.id) - refute User.has_mute?(user.id) - refute User.is_restricted?(user.id, ["Login"]) + refute CacheUser.has_warning?(user.id) + refute CacheUser.has_mute?(user.id) + refute CacheUser.is_restricted?(user.id, ["Login"]) {:ok, action} = Moderation.create_action(%{ @@ -33,9 +33,9 @@ defmodule Teiserver.Coordinator.ModerationTest do RefreshUserRestrictionsTask.refresh_user(user.id) # Did it take? - assert User.has_warning?(user.id) - refute User.has_mute?(user.id) - refute User.is_restricted?(user.id, ["Login"]) + assert CacheUser.has_warning?(user.id) + refute CacheUser.has_mute?(user.id) + refute CacheUser.is_restricted?(user.id, ["Login"]) # Now login %{socket: socket} = tachyon_auth_setup(user) diff --git a/test/teiserver/protocols/spring/spring_telemetry_test.exs b/test/teiserver/protocols/spring/spring_telemetry_test.exs index 4d75fe6cf..2739f06fa 100644 --- a/test/teiserver/protocols/spring/spring_telemetry_test.exs +++ b/test/teiserver/protocols/spring/spring_telemetry_test.exs @@ -100,16 +100,16 @@ defmodule Teiserver.SpringTelemetryTest do reply = _recv_raw(socket) assert reply == :timeout - assert Enum.count(Telemetry.list_anon_events()) == 0 - assert Enum.count(Telemetry.list_client_events()) == 0 + assert Enum.count(Telemetry.list_complex_anon_events()) == 0 + assert Enum.count(Telemetry.list_complex_client_events()) == 0 # Good data _send_raw(socket, "c.telemetry.log_client_event event_name e30= TXlWYWx1ZUdvZXNoZXJl\n") reply = _recv_raw(socket) assert reply == :timeout - assert Enum.count(Telemetry.list_anon_events()) == 0 - assert Enum.count(Telemetry.list_client_events()) == 1 + assert Enum.count(Telemetry.list_complex_anon_events()) == 0 + assert Enum.count(Telemetry.list_complex_client_events()) == 1 # Unauth %{socket: socket_raw} = raw_setup() @@ -118,8 +118,8 @@ defmodule Teiserver.SpringTelemetryTest do reply = _recv_raw(socket_raw) assert reply == :timeout - assert Enum.count(Telemetry.list_anon_events()) == 1 - assert Enum.count(Telemetry.list_client_events()) == 1 + assert Enum.count(Telemetry.list_complex_anon_events()) == 1 + assert Enum.count(Telemetry.list_complex_client_events()) == 1 end test "update_client_property call", %{socket: socket} do @@ -132,7 +132,7 @@ defmodule Teiserver.SpringTelemetryTest do reply = _recv_raw(socket) assert reply == :timeout - assert Enum.count(Telemetry.list_anon_properties()) == 0 + assert Enum.count(Telemetry.list_complex_anon_events()) == 0 assert Enum.count(Telemetry.list_client_properties()) == 0 # Good data @@ -144,7 +144,7 @@ defmodule Teiserver.SpringTelemetryTest do reply = _recv_raw(socket) assert reply == :timeout - assert Enum.count(Telemetry.list_anon_properties()) == 0 + assert Enum.count(Telemetry.list_complex_anon_events()) == 0 assert Enum.count(Telemetry.list_client_properties()) == 1 # Unauth @@ -159,7 +159,7 @@ defmodule Teiserver.SpringTelemetryTest do reply = _recv_raw(socket_raw) assert reply == :timeout - assert Enum.count(Telemetry.list_anon_properties()) == 1 + assert Enum.count(Telemetry.list_complex_anon_events()) == 1 assert Enum.count(Telemetry.list_client_properties()) == 1 end end diff --git a/test/teiserver_web/controllers/report/complex_client_event_controller_test.exs b/test/teiserver_web/controllers/report/complex_client_event_controller_test.exs index ad465186e..6c14e0949 100644 --- a/test/teiserver_web/controllers/report/complex_client_event_controller_test.exs +++ b/test/teiserver_web/controllers/report/complex_client_event_controller_test.exs @@ -9,7 +9,7 @@ defmodule TeiserverWeb.Report.ComplexClientEventControllerTest do end test "index", %{conn: conn} do - conn = get(conn, ~p"/telemetry/complex_client/summary") + conn = get(conn, ~p"/telemetry/complex_client_events/summary") assert html_response(conn, 200) end diff --git a/test/teiserver_web/live/microblog/blog/index_live_test.exs b/test/teiserver_web/live/microblog/blog/index_live_test.exs index 6ba5f660e..134451508 100644 --- a/test/teiserver_web/live/microblog/blog/index_live_test.exs +++ b/test/teiserver_web/live/microblog/blog/index_live_test.exs @@ -17,15 +17,33 @@ defmodule TeiserverWeb.Microblog.Blog.IndexLiveTest do tag2 = tag_fixture() tag3 = tag_fixture() - post1 = post_fixture(title: "Post 1 title", contents: "Post 1 line1\n\nPost 1 fold line") + post1 = + post_fixture( + title: "Post 1 title", + summary: "Post 1 line1", + contents: "Post 1 line1\n\nPost 1 fold line" + ) + _post1_tag1 = post_tag_fixture(post_id: post1.id, tag_id: tag1.id) _post1_tag2 = post_tag_fixture(post_id: post1.id, tag_id: tag2.id) - post2 = post_fixture(title: "Post 2 title", contents: "Post 2 line1\n\nPost 2 fold line") + post2 = + post_fixture( + title: "Post 2 title", + summary: "Post 2 line1", + contents: "Post 2 line1\n\nPost 2 fold line" + ) + _post2_tag1 = post_tag_fixture(post_id: post2.id, tag_id: tag1.id) _post2_tag3 = post_tag_fixture(post_id: post2.id, tag_id: tag3.id) - post3 = post_fixture(title: "Post 3 title", contents: "Post 3 line1\n\nPost 3 fold line") + post3 = + post_fixture( + title: "Post 3 title", + summary: "Post 3 line1", + contents: "Post 3 line1\n\nPost 3 fold line" + ) + _post3_tag2 = post_tag_fixture(post_id: post3.id, tag_id: tag2.id) _post3_tag3 = post_tag_fixture(post_id: post3.id, tag_id: tag3.id)