diff --git a/generated/schema.graphql b/generated/schema.graphql index 1b7c659c0..ad62470fd 100644 --- a/generated/schema.graphql +++ b/generated/schema.graphql @@ -22950,6 +22950,8 @@ type game_modes { archived_at: timestamptz cfg: String competitive_safe: Boolean! + players_per_team: Int + allow_short_handed_start: Boolean! created_at: timestamptz! description: String enabled: Boolean! @@ -23074,6 +23076,8 @@ input game_modes_bool_exp { archived_at: timestamptz_comparison_exp cfg: String_comparison_exp competitive_safe: Boolean_comparison_exp + players_per_team: Int_comparison_exp + allow_short_handed_start: Boolean_comparison_exp created_at: timestamptz_comparison_exp description: String_comparison_exp enabled: Boolean_comparison_exp @@ -23113,6 +23117,8 @@ input game_modes_insert_input { archived_at: timestamptz cfg: String competitive_safe: Boolean + players_per_team: Int + allow_short_handed_start: Boolean created_at: timestamptz description: String enabled: Boolean @@ -23189,6 +23195,8 @@ input game_modes_order_by { archived_at: order_by cfg: order_by competitive_safe: order_by + players_per_team: order_by + allow_short_handed_start: order_by created_at: order_by description: order_by enabled: order_by @@ -23221,6 +23229,8 @@ enum game_modes_select_column { """column name""" competitive_safe + players_per_team + allow_short_handed_start """column name""" created_at @@ -23257,6 +23267,8 @@ input game_modes_set_input { archived_at: timestamptz cfg: String competitive_safe: Boolean + players_per_team: Int + allow_short_handed_start: Boolean created_at: timestamptz description: String enabled: Boolean @@ -23284,6 +23296,8 @@ input game_modes_stream_cursor_value_input { archived_at: timestamptz cfg: String competitive_safe: Boolean + players_per_team: Int + allow_short_handed_start: Boolean created_at: timestamptz description: String enabled: Boolean @@ -23307,6 +23321,8 @@ enum game_modes_update_column { """column name""" competitive_safe + players_per_team + allow_short_handed_start """column name""" created_at @@ -40162,6 +40178,7 @@ type match_options { ): matches_aggregate! mr: Int! number_of_substitutes: Int! + min_players_per_lineup: Int overtime: Boolean! prefer_dedicated_server: Boolean! ready_setting: e_ready_settings_enum! @@ -40270,6 +40287,7 @@ type match_options_avg_fields { live_match_timeout: Float mr: Float number_of_substitutes: Float + min_players_per_lineup: Float round_restart_delay: Float tv_delay: Float veto_pick_timeout: Float @@ -40284,6 +40302,7 @@ input match_options_avg_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by @@ -40320,6 +40339,7 @@ input match_options_bool_exp { matches_aggregate: matches_aggregate_bool_exp mr: Int_comparison_exp number_of_substitutes: Int_comparison_exp + min_players_per_lineup: Int_comparison_exp overtime: Boolean_comparison_exp prefer_dedicated_server: Boolean_comparison_exp ready_setting: e_ready_settings_enum_comparison_exp @@ -40355,6 +40375,7 @@ input match_options_inc_input { live_match_timeout: Int mr: Int number_of_substitutes: Int + min_players_per_lineup: Int round_restart_delay: Int tv_delay: Int veto_pick_timeout: Int @@ -40386,6 +40407,7 @@ input match_options_insert_input { matches: matches_arr_rel_insert_input mr: Int number_of_substitutes: Int + min_players_per_lineup: Int overtime: Boolean prefer_dedicated_server: Boolean ready_setting: e_ready_settings_enum @@ -40413,6 +40435,7 @@ type match_options_max_fields { map_pool_id: uuid mr: Int number_of_substitutes: Int + min_players_per_lineup: Int regions: [String!] round_restart_delay: Int tv_delay: Int @@ -40432,6 +40455,7 @@ input match_options_max_order_by { map_pool_id: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by regions: order_by round_restart_delay: order_by tv_delay: order_by @@ -40449,6 +40473,7 @@ type match_options_min_fields { map_pool_id: uuid mr: Int number_of_substitutes: Int + min_players_per_lineup: Int regions: [String!] round_restart_delay: Int tv_delay: Int @@ -40468,6 +40493,7 @@ input match_options_min_order_by { map_pool_id: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by regions: order_by round_restart_delay: order_by tv_delay: order_by @@ -40529,6 +40555,7 @@ input match_options_order_by { matches_aggregate: matches_aggregate_order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by overtime: order_by prefer_dedicated_server: order_by ready_setting: order_by @@ -40610,6 +40637,7 @@ enum match_options_select_column { """column name""" number_of_substitutes + min_players_per_lineup """column name""" overtime @@ -40744,6 +40772,7 @@ input match_options_set_input { match_mode: e_match_mode_enum mr: Int number_of_substitutes: Int + min_players_per_lineup: Int overtime: Boolean prefer_dedicated_server: Boolean ready_setting: e_ready_settings_enum @@ -40764,6 +40793,7 @@ type match_options_stddev_fields { live_match_timeout: Float mr: Float number_of_substitutes: Float + min_players_per_lineup: Float round_restart_delay: Float tv_delay: Float veto_pick_timeout: Float @@ -40778,6 +40808,7 @@ input match_options_stddev_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by @@ -40790,6 +40821,7 @@ type match_options_stddev_pop_fields { live_match_timeout: Float mr: Float number_of_substitutes: Float + min_players_per_lineup: Float round_restart_delay: Float tv_delay: Float veto_pick_timeout: Float @@ -40804,6 +40836,7 @@ input match_options_stddev_pop_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by @@ -40816,6 +40849,7 @@ type match_options_stddev_samp_fields { live_match_timeout: Float mr: Float number_of_substitutes: Float + min_players_per_lineup: Float round_restart_delay: Float tv_delay: Float veto_pick_timeout: Float @@ -40830,6 +40864,7 @@ input match_options_stddev_samp_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by @@ -40867,6 +40902,7 @@ input match_options_stream_cursor_value_input { match_mode: e_match_mode_enum mr: Int number_of_substitutes: Int + min_players_per_lineup: Int overtime: Boolean prefer_dedicated_server: Boolean ready_setting: e_ready_settings_enum @@ -40887,6 +40923,7 @@ type match_options_sum_fields { live_match_timeout: Int mr: Int number_of_substitutes: Int + min_players_per_lineup: Int round_restart_delay: Int tv_delay: Int veto_pick_timeout: Int @@ -40901,6 +40938,7 @@ input match_options_sum_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by @@ -40966,6 +41004,7 @@ enum match_options_update_column { """column name""" number_of_substitutes + min_players_per_lineup """column name""" overtime @@ -41019,6 +41058,7 @@ type match_options_var_pop_fields { live_match_timeout: Float mr: Float number_of_substitutes: Float + min_players_per_lineup: Float round_restart_delay: Float tv_delay: Float veto_pick_timeout: Float @@ -41033,6 +41073,7 @@ input match_options_var_pop_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by @@ -41045,6 +41086,7 @@ type match_options_var_samp_fields { live_match_timeout: Float mr: Float number_of_substitutes: Float + min_players_per_lineup: Float round_restart_delay: Float tv_delay: Float veto_pick_timeout: Float @@ -41059,6 +41101,7 @@ input match_options_var_samp_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by @@ -41071,6 +41114,7 @@ type match_options_variance_fields { live_match_timeout: Float mr: Float number_of_substitutes: Float + min_players_per_lineup: Float round_restart_delay: Float tv_delay: Float veto_pick_timeout: Float @@ -41085,6 +41129,7 @@ input match_options_variance_order_by { live_match_timeout: order_by mr: order_by number_of_substitutes: order_by + min_players_per_lineup: order_by round_restart_delay: order_by tv_delay: order_by veto_pick_timeout: order_by diff --git a/generated/schema.ts b/generated/schema.ts index cf1294428..9dc132888 100644 --- a/generated/schema.ts +++ b/generated/schema.ts @@ -8751,6 +8751,8 @@ export interface game_modes { archived_at: (Scalars['timestamptz'] | null) cfg: (Scalars['String'] | null) competitive_safe: Scalars['Boolean'] + players_per_team: (Scalars['Int'] | null) + allow_short_handed_start: Scalars['Boolean'] created_at: Scalars['timestamptz'] description: (Scalars['String'] | null) enabled: Scalars['Boolean'] @@ -8840,11 +8842,11 @@ export interface game_modes_mutation_response { /** select columns of table "game_modes" */ -export type game_modes_select_column = 'archived_at' | 'cfg' | 'competitive_safe' | 'created_at' | 'description' | 'enabled' | 'extra_game_params' | 'icon' | 'id' | 'name' | 'slug' | 'updated_at' +export type game_modes_select_column = 'archived_at' | 'cfg' | 'competitive_safe' | 'players_per_team' | 'allow_short_handed_start' | 'created_at' | 'description' | 'enabled' | 'extra_game_params' | 'icon' | 'id' | 'name' | 'slug' | 'updated_at' /** update columns of table "game_modes" */ -export type game_modes_update_column = 'archived_at' | 'cfg' | 'competitive_safe' | 'created_at' | 'description' | 'enabled' | 'extra_game_params' | 'icon' | 'id' | 'name' | 'slug' | 'updated_at' +export type game_modes_update_column = 'archived_at' | 'cfg' | 'competitive_safe' | 'players_per_team' | 'allow_short_handed_start' | 'created_at' | 'description' | 'enabled' | 'extra_game_params' | 'icon' | 'id' | 'name' | 'slug' | 'updated_at' /** columns and relationships of "game_plugin_installs" */ @@ -13958,6 +13960,7 @@ export interface match_options { matches_aggregate: matches_aggregate mr: Scalars['Int'] number_of_substitutes: Scalars['Int'] + min_players_per_lineup: (Scalars['Int'] | null) overtime: Scalars['Boolean'] prefer_dedicated_server: Scalars['Boolean'] ready_setting: e_ready_settings_enum @@ -14011,6 +14014,7 @@ export interface match_options_avg_fields { live_match_timeout: (Scalars['Float'] | null) mr: (Scalars['Float'] | null) number_of_substitutes: (Scalars['Float'] | null) + min_players_per_lineup: (Scalars['Float'] | null) round_restart_delay: (Scalars['Float'] | null) tv_delay: (Scalars['Float'] | null) veto_pick_timeout: (Scalars['Float'] | null) @@ -14033,6 +14037,7 @@ export interface match_options_max_fields { map_pool_id: (Scalars['uuid'] | null) mr: (Scalars['Int'] | null) number_of_substitutes: (Scalars['Int'] | null) + min_players_per_lineup: (Scalars['Int'] | null) regions: (Scalars['String'][] | null) round_restart_delay: (Scalars['Int'] | null) tv_delay: (Scalars['Int'] | null) @@ -14052,6 +14057,7 @@ export interface match_options_min_fields { map_pool_id: (Scalars['uuid'] | null) mr: (Scalars['Int'] | null) number_of_substitutes: (Scalars['Int'] | null) + min_players_per_lineup: (Scalars['Int'] | null) regions: (Scalars['String'][] | null) round_restart_delay: (Scalars['Int'] | null) tv_delay: (Scalars['Int'] | null) @@ -14071,7 +14077,7 @@ export interface match_options_mutation_response { /** select columns of table "match_options" */ -export type match_options_select_column = 'auto_cancel_duration' | 'auto_cancellation' | 'best_of' | 'camera_allow_teammates' | 'camera_required' | 'check_in_setting' | 'coaches' | 'default_models' | 'game_mode_id' | 'halftime_pausematch' | 'id' | 'invite_code' | 'knife_round' | 'live_match_timeout' | 'map_pool_id' | 'map_veto' | 'match_mode' | 'mr' | 'number_of_substitutes' | 'overtime' | 'prefer_dedicated_server' | 'ready_setting' | 'region_veto' | 'regions' | 'round_restart_delay' | 'tech_timeout_setting' | 'timeout_setting' | 'tv_delay' | 'type' | 'veto_pick_timeout' +export type match_options_select_column = 'auto_cancel_duration' | 'auto_cancellation' | 'best_of' | 'camera_allow_teammates' | 'camera_required' | 'check_in_setting' | 'coaches' | 'default_models' | 'game_mode_id' | 'halftime_pausematch' | 'id' | 'invite_code' | 'knife_round' | 'live_match_timeout' | 'map_pool_id' | 'map_veto' | 'match_mode' | 'mr' | 'number_of_substitutes' | 'min_players_per_lineup' | 'overtime' | 'prefer_dedicated_server' | 'ready_setting' | 'region_veto' | 'regions' | 'round_restart_delay' | 'tech_timeout_setting' | 'timeout_setting' | 'tv_delay' | 'type' | 'veto_pick_timeout' /** select "match_options_aggregate_bool_exp_bool_and_arguments_columns" columns of table "match_options" */ @@ -14089,6 +14095,7 @@ export interface match_options_stddev_fields { live_match_timeout: (Scalars['Float'] | null) mr: (Scalars['Float'] | null) number_of_substitutes: (Scalars['Float'] | null) + min_players_per_lineup: (Scalars['Float'] | null) round_restart_delay: (Scalars['Float'] | null) tv_delay: (Scalars['Float'] | null) veto_pick_timeout: (Scalars['Float'] | null) @@ -14103,6 +14110,7 @@ export interface match_options_stddev_pop_fields { live_match_timeout: (Scalars['Float'] | null) mr: (Scalars['Float'] | null) number_of_substitutes: (Scalars['Float'] | null) + min_players_per_lineup: (Scalars['Float'] | null) round_restart_delay: (Scalars['Float'] | null) tv_delay: (Scalars['Float'] | null) veto_pick_timeout: (Scalars['Float'] | null) @@ -14117,6 +14125,7 @@ export interface match_options_stddev_samp_fields { live_match_timeout: (Scalars['Float'] | null) mr: (Scalars['Float'] | null) number_of_substitutes: (Scalars['Float'] | null) + min_players_per_lineup: (Scalars['Float'] | null) round_restart_delay: (Scalars['Float'] | null) tv_delay: (Scalars['Float'] | null) veto_pick_timeout: (Scalars['Float'] | null) @@ -14131,6 +14140,7 @@ export interface match_options_sum_fields { live_match_timeout: (Scalars['Int'] | null) mr: (Scalars['Int'] | null) number_of_substitutes: (Scalars['Int'] | null) + min_players_per_lineup: (Scalars['Int'] | null) round_restart_delay: (Scalars['Int'] | null) tv_delay: (Scalars['Int'] | null) veto_pick_timeout: (Scalars['Int'] | null) @@ -14139,7 +14149,7 @@ export interface match_options_sum_fields { /** update columns of table "match_options" */ -export type match_options_update_column = 'auto_cancel_duration' | 'auto_cancellation' | 'best_of' | 'camera_allow_teammates' | 'camera_required' | 'check_in_setting' | 'coaches' | 'default_models' | 'game_mode_id' | 'halftime_pausematch' | 'id' | 'invite_code' | 'knife_round' | 'live_match_timeout' | 'map_pool_id' | 'map_veto' | 'match_mode' | 'mr' | 'number_of_substitutes' | 'overtime' | 'prefer_dedicated_server' | 'ready_setting' | 'region_veto' | 'regions' | 'round_restart_delay' | 'tech_timeout_setting' | 'timeout_setting' | 'tv_delay' | 'type' | 'veto_pick_timeout' +export type match_options_update_column = 'auto_cancel_duration' | 'auto_cancellation' | 'best_of' | 'camera_allow_teammates' | 'camera_required' | 'check_in_setting' | 'coaches' | 'default_models' | 'game_mode_id' | 'halftime_pausematch' | 'id' | 'invite_code' | 'knife_round' | 'live_match_timeout' | 'map_pool_id' | 'map_veto' | 'match_mode' | 'mr' | 'number_of_substitutes' | 'min_players_per_lineup' | 'overtime' | 'prefer_dedicated_server' | 'ready_setting' | 'region_veto' | 'regions' | 'round_restart_delay' | 'tech_timeout_setting' | 'timeout_setting' | 'tv_delay' | 'type' | 'veto_pick_timeout' /** aggregate var_pop on columns */ @@ -14149,6 +14159,7 @@ export interface match_options_var_pop_fields { live_match_timeout: (Scalars['Float'] | null) mr: (Scalars['Float'] | null) number_of_substitutes: (Scalars['Float'] | null) + min_players_per_lineup: (Scalars['Float'] | null) round_restart_delay: (Scalars['Float'] | null) tv_delay: (Scalars['Float'] | null) veto_pick_timeout: (Scalars['Float'] | null) @@ -14163,6 +14174,7 @@ export interface match_options_var_samp_fields { live_match_timeout: (Scalars['Float'] | null) mr: (Scalars['Float'] | null) number_of_substitutes: (Scalars['Float'] | null) + min_players_per_lineup: (Scalars['Float'] | null) round_restart_delay: (Scalars['Float'] | null) tv_delay: (Scalars['Float'] | null) veto_pick_timeout: (Scalars['Float'] | null) @@ -14177,6 +14189,7 @@ export interface match_options_variance_fields { live_match_timeout: (Scalars['Float'] | null) mr: (Scalars['Float'] | null) number_of_substitutes: (Scalars['Float'] | null) + min_players_per_lineup: (Scalars['Float'] | null) round_restart_delay: (Scalars['Float'] | null) tv_delay: (Scalars['Float'] | null) veto_pick_timeout: (Scalars['Float'] | null) @@ -59461,6 +59474,8 @@ export interface game_modesGenqlSelection{ archived_at?: boolean | number cfg?: boolean | number competitive_safe?: boolean | number + players_per_team?: boolean | number + allow_short_handed_start?: boolean | number created_at?: boolean | number description?: boolean | number enabled?: boolean | number @@ -59551,11 +59566,11 @@ export interface game_modes_aggregate_fieldsGenqlSelection{ /** Boolean expression to filter rows from the table "game_modes". All fields are combined with a logical 'AND'. */ -export interface game_modes_bool_exp {_and?: (game_modes_bool_exp[] | null),_not?: (game_modes_bool_exp | null),_or?: (game_modes_bool_exp[] | null),archived_at?: (timestamptz_comparison_exp | null),cfg?: (String_comparison_exp | null),competitive_safe?: (Boolean_comparison_exp | null),created_at?: (timestamptz_comparison_exp | null),description?: (String_comparison_exp | null),enabled?: (Boolean_comparison_exp | null),extra_game_params?: (String_comparison_exp | null),icon?: (String_comparison_exp | null),id?: (uuid_comparison_exp | null),match_options?: (match_options_bool_exp | null),match_options_aggregate?: (match_options_aggregate_bool_exp | null),name?: (String_comparison_exp | null),plugins?: (game_mode_plugins_bool_exp | null),plugins_aggregate?: (game_mode_plugins_aggregate_bool_exp | null),runtime_conflicts?: (jsonb_comparison_exp | null),slug?: (String_comparison_exp | null),supported_runtimes?: (jsonb_comparison_exp | null),updated_at?: (timestamptz_comparison_exp | null)} +export interface game_modes_bool_exp {_and?: (game_modes_bool_exp[] | null),_not?: (game_modes_bool_exp | null),_or?: (game_modes_bool_exp[] | null),archived_at?: (timestamptz_comparison_exp | null),cfg?: (String_comparison_exp | null),competitive_safe?: (Boolean_comparison_exp | null),players_per_team?: (Int_comparison_exp | null),allow_short_handed_start?: (Boolean_comparison_exp | null),created_at?: (timestamptz_comparison_exp | null),description?: (String_comparison_exp | null),enabled?: (Boolean_comparison_exp | null),extra_game_params?: (String_comparison_exp | null),icon?: (String_comparison_exp | null),id?: (uuid_comparison_exp | null),match_options?: (match_options_bool_exp | null),match_options_aggregate?: (match_options_aggregate_bool_exp | null),name?: (String_comparison_exp | null),plugins?: (game_mode_plugins_bool_exp | null),plugins_aggregate?: (game_mode_plugins_aggregate_bool_exp | null),runtime_conflicts?: (jsonb_comparison_exp | null),slug?: (String_comparison_exp | null),supported_runtimes?: (jsonb_comparison_exp | null),updated_at?: (timestamptz_comparison_exp | null)} /** input type for inserting data into table "game_modes" */ -export interface game_modes_insert_input {archived_at?: (Scalars['timestamptz'] | null),cfg?: (Scalars['String'] | null),competitive_safe?: (Scalars['Boolean'] | null),created_at?: (Scalars['timestamptz'] | null),description?: (Scalars['String'] | null),enabled?: (Scalars['Boolean'] | null),extra_game_params?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),id?: (Scalars['uuid'] | null),match_options?: (match_options_arr_rel_insert_input | null),name?: (Scalars['String'] | null),plugins?: (game_mode_plugins_arr_rel_insert_input | null),slug?: (Scalars['String'] | null),updated_at?: (Scalars['timestamptz'] | null)} +export interface game_modes_insert_input {archived_at?: (Scalars['timestamptz'] | null),cfg?: (Scalars['String'] | null),competitive_safe?: (Scalars['Boolean'] | null),players_per_team?: (Scalars['Int'] | null),allow_short_handed_start?: (Scalars['Boolean'] | null),created_at?: (Scalars['timestamptz'] | null),description?: (Scalars['String'] | null),enabled?: (Scalars['Boolean'] | null),extra_game_params?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),id?: (Scalars['uuid'] | null),match_options?: (match_options_arr_rel_insert_input | null),name?: (Scalars['String'] | null),plugins?: (game_mode_plugins_arr_rel_insert_input | null),slug?: (Scalars['String'] | null),updated_at?: (Scalars['timestamptz'] | null)} /** aggregate max on columns */ @@ -59614,7 +59629,7 @@ export interface game_modes_on_conflict {constraint: game_modes_constraint,updat /** Ordering options when selecting data from "game_modes". */ -export interface game_modes_order_by {archived_at?: (order_by | null),cfg?: (order_by | null),competitive_safe?: (order_by | null),created_at?: (order_by | null),description?: (order_by | null),enabled?: (order_by | null),extra_game_params?: (order_by | null),icon?: (order_by | null),id?: (order_by | null),match_options_aggregate?: (match_options_aggregate_order_by | null),name?: (order_by | null),plugins_aggregate?: (game_mode_plugins_aggregate_order_by | null),runtime_conflicts?: (order_by | null),slug?: (order_by | null),supported_runtimes?: (order_by | null),updated_at?: (order_by | null)} +export interface game_modes_order_by {archived_at?: (order_by | null),cfg?: (order_by | null),competitive_safe?: (order_by | null),players_per_team?: (order_by | null),allow_short_handed_start?: (order_by | null),created_at?: (order_by | null),description?: (order_by | null),enabled?: (order_by | null),extra_game_params?: (order_by | null),icon?: (order_by | null),id?: (order_by | null),match_options_aggregate?: (match_options_aggregate_order_by | null),name?: (order_by | null),plugins_aggregate?: (game_mode_plugins_aggregate_order_by | null),runtime_conflicts?: (order_by | null),slug?: (order_by | null),supported_runtimes?: (order_by | null),updated_at?: (order_by | null)} /** primary key columns input for table: game_modes */ @@ -59622,7 +59637,7 @@ export interface game_modes_pk_columns_input {id: Scalars['uuid']} /** input type for updating data in table "game_modes" */ -export interface game_modes_set_input {archived_at?: (Scalars['timestamptz'] | null),cfg?: (Scalars['String'] | null),competitive_safe?: (Scalars['Boolean'] | null),created_at?: (Scalars['timestamptz'] | null),description?: (Scalars['String'] | null),enabled?: (Scalars['Boolean'] | null),extra_game_params?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),id?: (Scalars['uuid'] | null),name?: (Scalars['String'] | null),slug?: (Scalars['String'] | null),updated_at?: (Scalars['timestamptz'] | null)} +export interface game_modes_set_input {archived_at?: (Scalars['timestamptz'] | null),cfg?: (Scalars['String'] | null),competitive_safe?: (Scalars['Boolean'] | null),players_per_team?: (Scalars['Int'] | null),allow_short_handed_start?: (Scalars['Boolean'] | null),created_at?: (Scalars['timestamptz'] | null),description?: (Scalars['String'] | null),enabled?: (Scalars['Boolean'] | null),extra_game_params?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),id?: (Scalars['uuid'] | null),name?: (Scalars['String'] | null),slug?: (Scalars['String'] | null),updated_at?: (Scalars['timestamptz'] | null)} /** Streaming cursor of the table "game_modes" */ @@ -59634,7 +59649,7 @@ ordering?: (cursor_ordering | null)} /** Initial value of the column from where the streaming should start */ -export interface game_modes_stream_cursor_value_input {archived_at?: (Scalars['timestamptz'] | null),cfg?: (Scalars['String'] | null),competitive_safe?: (Scalars['Boolean'] | null),created_at?: (Scalars['timestamptz'] | null),description?: (Scalars['String'] | null),enabled?: (Scalars['Boolean'] | null),extra_game_params?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),id?: (Scalars['uuid'] | null),name?: (Scalars['String'] | null),slug?: (Scalars['String'] | null),updated_at?: (Scalars['timestamptz'] | null)} +export interface game_modes_stream_cursor_value_input {archived_at?: (Scalars['timestamptz'] | null),cfg?: (Scalars['String'] | null),competitive_safe?: (Scalars['Boolean'] | null),players_per_team?: (Scalars['Int'] | null),allow_short_handed_start?: (Scalars['Boolean'] | null),created_at?: (Scalars['timestamptz'] | null),description?: (Scalars['String'] | null),enabled?: (Scalars['Boolean'] | null),extra_game_params?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),id?: (Scalars['uuid'] | null),name?: (Scalars['String'] | null),slug?: (Scalars['String'] | null),updated_at?: (Scalars['timestamptz'] | null)} export interface game_modes_updates { /** sets the columns of the filtered rows to the given values */ @@ -68348,6 +68363,7 @@ export interface match_optionsGenqlSelection{ where?: (matches_bool_exp | null)} }) mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number overtime?: boolean | number prefer_dedicated_server?: boolean | number ready_setting?: boolean | number @@ -68422,6 +68438,7 @@ export interface match_options_avg_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68431,19 +68448,19 @@ export interface match_options_avg_fieldsGenqlSelection{ /** order by avg() on columns of table "match_options" */ -export interface match_options_avg_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_avg_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** Boolean expression to filter rows from the table "match_options". All fields are combined with a logical 'AND'. */ -export interface match_options_bool_exp {_and?: (match_options_bool_exp[] | null),_not?: (match_options_bool_exp | null),_or?: (match_options_bool_exp[] | null),auto_cancel_duration?: (Int_comparison_exp | null),auto_cancellation?: (Boolean_comparison_exp | null),best_of?: (Int_comparison_exp | null),camera_allow_teammates?: (Boolean_comparison_exp | null),camera_required?: (Boolean_comparison_exp | null),check_in_setting?: (e_check_in_settings_enum_comparison_exp | null),coaches?: (Boolean_comparison_exp | null),default_models?: (Boolean_comparison_exp | null),game_mode?: (game_modes_bool_exp | null),game_mode_id?: (uuid_comparison_exp | null),halftime_pausematch?: (Boolean_comparison_exp | null),has_active_matches?: (Boolean_comparison_exp | null),id?: (uuid_comparison_exp | null),invite_code?: (String_comparison_exp | null),knife_round?: (Boolean_comparison_exp | null),live_match_timeout?: (Int_comparison_exp | null),map_pool?: (map_pools_bool_exp | null),map_pool_id?: (uuid_comparison_exp | null),map_veto?: (Boolean_comparison_exp | null),match_mode?: (e_match_mode_enum_comparison_exp | null),matches?: (matches_bool_exp | null),matches_aggregate?: (matches_aggregate_bool_exp | null),mr?: (Int_comparison_exp | null),number_of_substitutes?: (Int_comparison_exp | null),overtime?: (Boolean_comparison_exp | null),prefer_dedicated_server?: (Boolean_comparison_exp | null),ready_setting?: (e_ready_settings_enum_comparison_exp | null),region_veto?: (Boolean_comparison_exp | null),regions?: (String_array_comparison_exp | null),round_restart_delay?: (Int_comparison_exp | null),tech_timeout_setting?: (e_timeout_settings_enum_comparison_exp | null),timeout_setting?: (e_timeout_settings_enum_comparison_exp | null),tournament?: (tournaments_bool_exp | null),tournament_bracket?: (tournament_brackets_bool_exp | null),tournament_stage?: (tournament_stages_bool_exp | null),tv_delay?: (Int_comparison_exp | null),type?: (e_match_types_enum_comparison_exp | null),veto_pick_timeout?: (Int_comparison_exp | null)} +export interface match_options_bool_exp {_and?: (match_options_bool_exp[] | null),_not?: (match_options_bool_exp | null),_or?: (match_options_bool_exp[] | null),auto_cancel_duration?: (Int_comparison_exp | null),auto_cancellation?: (Boolean_comparison_exp | null),best_of?: (Int_comparison_exp | null),camera_allow_teammates?: (Boolean_comparison_exp | null),camera_required?: (Boolean_comparison_exp | null),check_in_setting?: (e_check_in_settings_enum_comparison_exp | null),coaches?: (Boolean_comparison_exp | null),default_models?: (Boolean_comparison_exp | null),game_mode?: (game_modes_bool_exp | null),game_mode_id?: (uuid_comparison_exp | null),halftime_pausematch?: (Boolean_comparison_exp | null),has_active_matches?: (Boolean_comparison_exp | null),id?: (uuid_comparison_exp | null),invite_code?: (String_comparison_exp | null),knife_round?: (Boolean_comparison_exp | null),live_match_timeout?: (Int_comparison_exp | null),map_pool?: (map_pools_bool_exp | null),map_pool_id?: (uuid_comparison_exp | null),map_veto?: (Boolean_comparison_exp | null),match_mode?: (e_match_mode_enum_comparison_exp | null),matches?: (matches_bool_exp | null),matches_aggregate?: (matches_aggregate_bool_exp | null),mr?: (Int_comparison_exp | null),number_of_substitutes?: (Int_comparison_exp | null),min_players_per_lineup?: (Int_comparison_exp | null),overtime?: (Boolean_comparison_exp | null),prefer_dedicated_server?: (Boolean_comparison_exp | null),ready_setting?: (e_ready_settings_enum_comparison_exp | null),region_veto?: (Boolean_comparison_exp | null),regions?: (String_array_comparison_exp | null),round_restart_delay?: (Int_comparison_exp | null),tech_timeout_setting?: (e_timeout_settings_enum_comparison_exp | null),timeout_setting?: (e_timeout_settings_enum_comparison_exp | null),tournament?: (tournaments_bool_exp | null),tournament_bracket?: (tournament_brackets_bool_exp | null),tournament_stage?: (tournament_stages_bool_exp | null),tv_delay?: (Int_comparison_exp | null),type?: (e_match_types_enum_comparison_exp | null),veto_pick_timeout?: (Int_comparison_exp | null)} /** input type for incrementing numeric columns in table "match_options" */ -export interface match_options_inc_input {auto_cancel_duration?: (Scalars['Int'] | null),best_of?: (Scalars['Int'] | null),live_match_timeout?: (Scalars['Int'] | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),round_restart_delay?: (Scalars['Int'] | null),tv_delay?: (Scalars['Int'] | null),veto_pick_timeout?: (Scalars['Int'] | null)} +export interface match_options_inc_input {auto_cancel_duration?: (Scalars['Int'] | null),best_of?: (Scalars['Int'] | null),live_match_timeout?: (Scalars['Int'] | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),min_players_per_lineup?: (Scalars['Int'] | null),round_restart_delay?: (Scalars['Int'] | null),tv_delay?: (Scalars['Int'] | null),veto_pick_timeout?: (Scalars['Int'] | null)} /** input type for inserting data into table "match_options" */ -export interface match_options_insert_input {auto_cancel_duration?: (Scalars['Int'] | null),auto_cancellation?: (Scalars['Boolean'] | null),best_of?: (Scalars['Int'] | null),camera_allow_teammates?: (Scalars['Boolean'] | null),camera_required?: (Scalars['Boolean'] | null),check_in_setting?: (e_check_in_settings_enum | null),coaches?: (Scalars['Boolean'] | null),default_models?: (Scalars['Boolean'] | null),game_mode?: (game_modes_obj_rel_insert_input | null),game_mode_id?: (Scalars['uuid'] | null),halftime_pausematch?: (Scalars['Boolean'] | null),id?: (Scalars['uuid'] | null),invite_code?: (Scalars['String'] | null),knife_round?: (Scalars['Boolean'] | null),live_match_timeout?: (Scalars['Int'] | null),map_pool?: (map_pools_obj_rel_insert_input | null),map_pool_id?: (Scalars['uuid'] | null),map_veto?: (Scalars['Boolean'] | null),match_mode?: (e_match_mode_enum | null),matches?: (matches_arr_rel_insert_input | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),overtime?: (Scalars['Boolean'] | null),prefer_dedicated_server?: (Scalars['Boolean'] | null),ready_setting?: (e_ready_settings_enum | null),region_veto?: (Scalars['Boolean'] | null),regions?: (Scalars['String'][] | null),round_restart_delay?: (Scalars['Int'] | null),tech_timeout_setting?: (e_timeout_settings_enum | null),timeout_setting?: (e_timeout_settings_enum | null),tournament?: (tournaments_obj_rel_insert_input | null),tournament_bracket?: (tournament_brackets_obj_rel_insert_input | null),tournament_stage?: (tournament_stages_obj_rel_insert_input | null),tv_delay?: (Scalars['Int'] | null),type?: (e_match_types_enum | null),veto_pick_timeout?: (Scalars['Int'] | null)} +export interface match_options_insert_input {auto_cancel_duration?: (Scalars['Int'] | null),auto_cancellation?: (Scalars['Boolean'] | null),best_of?: (Scalars['Int'] | null),camera_allow_teammates?: (Scalars['Boolean'] | null),camera_required?: (Scalars['Boolean'] | null),check_in_setting?: (e_check_in_settings_enum | null),coaches?: (Scalars['Boolean'] | null),default_models?: (Scalars['Boolean'] | null),game_mode?: (game_modes_obj_rel_insert_input | null),game_mode_id?: (Scalars['uuid'] | null),halftime_pausematch?: (Scalars['Boolean'] | null),id?: (Scalars['uuid'] | null),invite_code?: (Scalars['String'] | null),knife_round?: (Scalars['Boolean'] | null),live_match_timeout?: (Scalars['Int'] | null),map_pool?: (map_pools_obj_rel_insert_input | null),map_pool_id?: (Scalars['uuid'] | null),map_veto?: (Scalars['Boolean'] | null),match_mode?: (e_match_mode_enum | null),matches?: (matches_arr_rel_insert_input | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),min_players_per_lineup?: (Scalars['Int'] | null),overtime?: (Scalars['Boolean'] | null),prefer_dedicated_server?: (Scalars['Boolean'] | null),ready_setting?: (e_ready_settings_enum | null),region_veto?: (Scalars['Boolean'] | null),regions?: (Scalars['String'][] | null),round_restart_delay?: (Scalars['Int'] | null),tech_timeout_setting?: (e_timeout_settings_enum | null),timeout_setting?: (e_timeout_settings_enum | null),tournament?: (tournaments_obj_rel_insert_input | null),tournament_bracket?: (tournament_brackets_obj_rel_insert_input | null),tournament_stage?: (tournament_stages_obj_rel_insert_input | null),tv_delay?: (Scalars['Int'] | null),type?: (e_match_types_enum | null),veto_pick_timeout?: (Scalars['Int'] | null)} /** aggregate max on columns */ @@ -68457,6 +68474,7 @@ export interface match_options_max_fieldsGenqlSelection{ map_pool_id?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number regions?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number @@ -68467,7 +68485,7 @@ export interface match_options_max_fieldsGenqlSelection{ /** order by max() on columns of table "match_options" */ -export interface match_options_max_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),game_mode_id?: (order_by | null),id?: (order_by | null),invite_code?: (order_by | null),live_match_timeout?: (order_by | null),map_pool_id?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),regions?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_max_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),game_mode_id?: (order_by | null),id?: (order_by | null),invite_code?: (order_by | null),live_match_timeout?: (order_by | null),map_pool_id?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),regions?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** aggregate min on columns */ @@ -68481,6 +68499,7 @@ export interface match_options_min_fieldsGenqlSelection{ map_pool_id?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number regions?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number @@ -68491,7 +68510,7 @@ export interface match_options_min_fieldsGenqlSelection{ /** order by min() on columns of table "match_options" */ -export interface match_options_min_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),game_mode_id?: (order_by | null),id?: (order_by | null),invite_code?: (order_by | null),live_match_timeout?: (order_by | null),map_pool_id?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),regions?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_min_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),game_mode_id?: (order_by | null),id?: (order_by | null),invite_code?: (order_by | null),live_match_timeout?: (order_by | null),map_pool_id?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),regions?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** response of any mutation on the table "match_options" */ @@ -68516,7 +68535,7 @@ export interface match_options_on_conflict {constraint: match_options_constraint /** Ordering options when selecting data from "match_options". */ -export interface match_options_order_by {auto_cancel_duration?: (order_by | null),auto_cancellation?: (order_by | null),best_of?: (order_by | null),camera_allow_teammates?: (order_by | null),camera_required?: (order_by | null),check_in_setting?: (order_by | null),coaches?: (order_by | null),default_models?: (order_by | null),game_mode?: (game_modes_order_by | null),game_mode_id?: (order_by | null),halftime_pausematch?: (order_by | null),has_active_matches?: (order_by | null),id?: (order_by | null),invite_code?: (order_by | null),knife_round?: (order_by | null),live_match_timeout?: (order_by | null),map_pool?: (map_pools_order_by | null),map_pool_id?: (order_by | null),map_veto?: (order_by | null),match_mode?: (order_by | null),matches_aggregate?: (matches_aggregate_order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),overtime?: (order_by | null),prefer_dedicated_server?: (order_by | null),ready_setting?: (order_by | null),region_veto?: (order_by | null),regions?: (order_by | null),round_restart_delay?: (order_by | null),tech_timeout_setting?: (order_by | null),timeout_setting?: (order_by | null),tournament?: (tournaments_order_by | null),tournament_bracket?: (tournament_brackets_order_by | null),tournament_stage?: (tournament_stages_order_by | null),tv_delay?: (order_by | null),type?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_order_by {auto_cancel_duration?: (order_by | null),auto_cancellation?: (order_by | null),best_of?: (order_by | null),camera_allow_teammates?: (order_by | null),camera_required?: (order_by | null),check_in_setting?: (order_by | null),coaches?: (order_by | null),default_models?: (order_by | null),game_mode?: (game_modes_order_by | null),game_mode_id?: (order_by | null),halftime_pausematch?: (order_by | null),has_active_matches?: (order_by | null),id?: (order_by | null),invite_code?: (order_by | null),knife_round?: (order_by | null),live_match_timeout?: (order_by | null),map_pool?: (map_pools_order_by | null),map_pool_id?: (order_by | null),map_veto?: (order_by | null),match_mode?: (order_by | null),matches_aggregate?: (matches_aggregate_order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),overtime?: (order_by | null),prefer_dedicated_server?: (order_by | null),ready_setting?: (order_by | null),region_veto?: (order_by | null),regions?: (order_by | null),round_restart_delay?: (order_by | null),tech_timeout_setting?: (order_by | null),timeout_setting?: (order_by | null),tournament?: (tournaments_order_by | null),tournament_bracket?: (tournament_brackets_order_by | null),tournament_stage?: (tournament_stages_order_by | null),tv_delay?: (order_by | null),type?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** primary key columns input for table: match_options */ @@ -68524,7 +68543,7 @@ export interface match_options_pk_columns_input {id: Scalars['uuid']} /** input type for updating data in table "match_options" */ -export interface match_options_set_input {auto_cancel_duration?: (Scalars['Int'] | null),auto_cancellation?: (Scalars['Boolean'] | null),best_of?: (Scalars['Int'] | null),camera_allow_teammates?: (Scalars['Boolean'] | null),camera_required?: (Scalars['Boolean'] | null),check_in_setting?: (e_check_in_settings_enum | null),coaches?: (Scalars['Boolean'] | null),default_models?: (Scalars['Boolean'] | null),game_mode_id?: (Scalars['uuid'] | null),halftime_pausematch?: (Scalars['Boolean'] | null),id?: (Scalars['uuid'] | null),invite_code?: (Scalars['String'] | null),knife_round?: (Scalars['Boolean'] | null),live_match_timeout?: (Scalars['Int'] | null),map_pool_id?: (Scalars['uuid'] | null),map_veto?: (Scalars['Boolean'] | null),match_mode?: (e_match_mode_enum | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),overtime?: (Scalars['Boolean'] | null),prefer_dedicated_server?: (Scalars['Boolean'] | null),ready_setting?: (e_ready_settings_enum | null),region_veto?: (Scalars['Boolean'] | null),regions?: (Scalars['String'][] | null),round_restart_delay?: (Scalars['Int'] | null),tech_timeout_setting?: (e_timeout_settings_enum | null),timeout_setting?: (e_timeout_settings_enum | null),tv_delay?: (Scalars['Int'] | null),type?: (e_match_types_enum | null),veto_pick_timeout?: (Scalars['Int'] | null)} +export interface match_options_set_input {auto_cancel_duration?: (Scalars['Int'] | null),auto_cancellation?: (Scalars['Boolean'] | null),best_of?: (Scalars['Int'] | null),camera_allow_teammates?: (Scalars['Boolean'] | null),camera_required?: (Scalars['Boolean'] | null),check_in_setting?: (e_check_in_settings_enum | null),coaches?: (Scalars['Boolean'] | null),default_models?: (Scalars['Boolean'] | null),game_mode_id?: (Scalars['uuid'] | null),halftime_pausematch?: (Scalars['Boolean'] | null),id?: (Scalars['uuid'] | null),invite_code?: (Scalars['String'] | null),knife_round?: (Scalars['Boolean'] | null),live_match_timeout?: (Scalars['Int'] | null),map_pool_id?: (Scalars['uuid'] | null),map_veto?: (Scalars['Boolean'] | null),match_mode?: (e_match_mode_enum | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),min_players_per_lineup?: (Scalars['Int'] | null),overtime?: (Scalars['Boolean'] | null),prefer_dedicated_server?: (Scalars['Boolean'] | null),ready_setting?: (e_ready_settings_enum | null),region_veto?: (Scalars['Boolean'] | null),regions?: (Scalars['String'][] | null),round_restart_delay?: (Scalars['Int'] | null),tech_timeout_setting?: (e_timeout_settings_enum | null),timeout_setting?: (e_timeout_settings_enum | null),tv_delay?: (Scalars['Int'] | null),type?: (e_match_types_enum | null),veto_pick_timeout?: (Scalars['Int'] | null)} /** aggregate stddev on columns */ @@ -68534,6 +68553,7 @@ export interface match_options_stddev_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68543,7 +68563,7 @@ export interface match_options_stddev_fieldsGenqlSelection{ /** order by stddev() on columns of table "match_options" */ -export interface match_options_stddev_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_stddev_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** aggregate stddev_pop on columns */ @@ -68553,6 +68573,7 @@ export interface match_options_stddev_pop_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68562,7 +68583,7 @@ export interface match_options_stddev_pop_fieldsGenqlSelection{ /** order by stddev_pop() on columns of table "match_options" */ -export interface match_options_stddev_pop_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_stddev_pop_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** aggregate stddev_samp on columns */ @@ -68572,6 +68593,7 @@ export interface match_options_stddev_samp_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68581,7 +68603,7 @@ export interface match_options_stddev_samp_fieldsGenqlSelection{ /** order by stddev_samp() on columns of table "match_options" */ -export interface match_options_stddev_samp_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_stddev_samp_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** Streaming cursor of the table "match_options" */ @@ -68593,7 +68615,7 @@ ordering?: (cursor_ordering | null)} /** Initial value of the column from where the streaming should start */ -export interface match_options_stream_cursor_value_input {auto_cancel_duration?: (Scalars['Int'] | null),auto_cancellation?: (Scalars['Boolean'] | null),best_of?: (Scalars['Int'] | null),camera_allow_teammates?: (Scalars['Boolean'] | null),camera_required?: (Scalars['Boolean'] | null),check_in_setting?: (e_check_in_settings_enum | null),coaches?: (Scalars['Boolean'] | null),default_models?: (Scalars['Boolean'] | null),game_mode_id?: (Scalars['uuid'] | null),halftime_pausematch?: (Scalars['Boolean'] | null),id?: (Scalars['uuid'] | null),invite_code?: (Scalars['String'] | null),knife_round?: (Scalars['Boolean'] | null),live_match_timeout?: (Scalars['Int'] | null),map_pool_id?: (Scalars['uuid'] | null),map_veto?: (Scalars['Boolean'] | null),match_mode?: (e_match_mode_enum | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),overtime?: (Scalars['Boolean'] | null),prefer_dedicated_server?: (Scalars['Boolean'] | null),ready_setting?: (e_ready_settings_enum | null),region_veto?: (Scalars['Boolean'] | null),regions?: (Scalars['String'][] | null),round_restart_delay?: (Scalars['Int'] | null),tech_timeout_setting?: (e_timeout_settings_enum | null),timeout_setting?: (e_timeout_settings_enum | null),tv_delay?: (Scalars['Int'] | null),type?: (e_match_types_enum | null),veto_pick_timeout?: (Scalars['Int'] | null)} +export interface match_options_stream_cursor_value_input {auto_cancel_duration?: (Scalars['Int'] | null),auto_cancellation?: (Scalars['Boolean'] | null),best_of?: (Scalars['Int'] | null),camera_allow_teammates?: (Scalars['Boolean'] | null),camera_required?: (Scalars['Boolean'] | null),check_in_setting?: (e_check_in_settings_enum | null),coaches?: (Scalars['Boolean'] | null),default_models?: (Scalars['Boolean'] | null),game_mode_id?: (Scalars['uuid'] | null),halftime_pausematch?: (Scalars['Boolean'] | null),id?: (Scalars['uuid'] | null),invite_code?: (Scalars['String'] | null),knife_round?: (Scalars['Boolean'] | null),live_match_timeout?: (Scalars['Int'] | null),map_pool_id?: (Scalars['uuid'] | null),map_veto?: (Scalars['Boolean'] | null),match_mode?: (e_match_mode_enum | null),mr?: (Scalars['Int'] | null),number_of_substitutes?: (Scalars['Int'] | null),min_players_per_lineup?: (Scalars['Int'] | null),overtime?: (Scalars['Boolean'] | null),prefer_dedicated_server?: (Scalars['Boolean'] | null),ready_setting?: (e_ready_settings_enum | null),region_veto?: (Scalars['Boolean'] | null),regions?: (Scalars['String'][] | null),round_restart_delay?: (Scalars['Int'] | null),tech_timeout_setting?: (e_timeout_settings_enum | null),timeout_setting?: (e_timeout_settings_enum | null),tv_delay?: (Scalars['Int'] | null),type?: (e_match_types_enum | null),veto_pick_timeout?: (Scalars['Int'] | null)} /** aggregate sum on columns */ @@ -68603,6 +68625,7 @@ export interface match_options_sum_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68612,7 +68635,7 @@ export interface match_options_sum_fieldsGenqlSelection{ /** order by sum() on columns of table "match_options" */ -export interface match_options_sum_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_sum_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} export interface match_options_updates { /** increments the numeric columns with given value of the filtered values */ @@ -68630,6 +68653,7 @@ export interface match_options_var_pop_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68639,7 +68663,7 @@ export interface match_options_var_pop_fieldsGenqlSelection{ /** order by var_pop() on columns of table "match_options" */ -export interface match_options_var_pop_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_var_pop_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** aggregate var_samp on columns */ @@ -68649,6 +68673,7 @@ export interface match_options_var_samp_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68658,7 +68683,7 @@ export interface match_options_var_samp_fieldsGenqlSelection{ /** order by var_samp() on columns of table "match_options" */ -export interface match_options_var_samp_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_var_samp_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** aggregate variance on columns */ @@ -68668,6 +68693,7 @@ export interface match_options_variance_fieldsGenqlSelection{ live_match_timeout?: boolean | number mr?: boolean | number number_of_substitutes?: boolean | number + min_players_per_lineup?: boolean | number round_restart_delay?: boolean | number tv_delay?: boolean | number veto_pick_timeout?: boolean | number @@ -68677,7 +68703,7 @@ export interface match_options_variance_fieldsGenqlSelection{ /** order by variance() on columns of table "match_options" */ -export interface match_options_variance_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} +export interface match_options_variance_order_by {auto_cancel_duration?: (order_by | null),best_of?: (order_by | null),live_match_timeout?: (order_by | null),mr?: (order_by | null),number_of_substitutes?: (order_by | null),min_players_per_lineup?: (order_by | null),round_restart_delay?: (order_by | null),tv_delay?: (order_by | null),veto_pick_timeout?: (order_by | null)} /** columns and relationships of "match_region_veto_picks" */ @@ -151602,6 +151628,8 @@ export const enumGameModesSelectColumn = { archived_at: 'archived_at' as const, cfg: 'cfg' as const, competitive_safe: 'competitive_safe' as const, + players_per_team: 'players_per_team' as const, + allow_short_handed_start: 'allow_short_handed_start' as const, created_at: 'created_at' as const, description: 'description' as const, enabled: 'enabled' as const, @@ -151617,6 +151645,8 @@ export const enumGameModesUpdateColumn = { archived_at: 'archived_at' as const, cfg: 'cfg' as const, competitive_safe: 'competitive_safe' as const, + players_per_team: 'players_per_team' as const, + allow_short_handed_start: 'allow_short_handed_start' as const, created_at: 'created_at' as const, description: 'description' as const, enabled: 'enabled' as const, @@ -152754,6 +152784,7 @@ export const enumMatchOptionsSelectColumn = { match_mode: 'match_mode' as const, mr: 'mr' as const, number_of_substitutes: 'number_of_substitutes' as const, + min_players_per_lineup: 'min_players_per_lineup' as const, overtime: 'overtime' as const, prefer_dedicated_server: 'prefer_dedicated_server' as const, ready_setting: 'ready_setting' as const, @@ -152815,6 +152846,7 @@ export const enumMatchOptionsUpdateColumn = { match_mode: 'match_mode' as const, mr: 'mr' as const, number_of_substitutes: 'number_of_substitutes' as const, + min_players_per_lineup: 'min_players_per_lineup' as const, overtime: 'overtime' as const, prefer_dedicated_server: 'prefer_dedicated_server' as const, ready_setting: 'ready_setting' as const, diff --git a/generated/types.ts b/generated/types.ts index 013b86380..f3859b26f 100644 --- a/generated/types.ts +++ b/generated/types.ts @@ -32929,6 +32929,12 @@ export default { "competitive_safe": [ 6 ], + "allow_short_handed_start": [ + 6 + ], + "players_per_team": [ + 41 + ], "created_at": [ 5243 ], @@ -33117,6 +33123,12 @@ export default { "competitive_safe": [ 7 ], + "allow_short_handed_start": [ + 7 + ], + "players_per_team": [ + 42 + ], "created_at": [ 5244 ], @@ -33177,6 +33189,12 @@ export default { "competitive_safe": [ 6 ], + "allow_short_handed_start": [ + 6 + ], + "players_per_team": [ + 41 + ], "created_at": [ 5243 ], @@ -33330,6 +33348,12 @@ export default { "competitive_safe": [ 3648 ], + "allow_short_handed_start": [ + 3648 + ], + "players_per_team": [ + 3648 + ], "created_at": [ 3648 ], @@ -33392,6 +33416,12 @@ export default { "competitive_safe": [ 6 ], + "allow_short_handed_start": [ + 6 + ], + "players_per_team": [ + 41 + ], "created_at": [ 5243 ], @@ -33444,6 +33474,12 @@ export default { "competitive_safe": [ 6 ], + "allow_short_handed_start": [ + 6 + ], + "players_per_team": [ + 41 + ], "created_at": [ 5243 ], @@ -59332,6 +59368,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "overtime": [ 6 ], @@ -59566,6 +59605,9 @@ export default { "number_of_substitutes": [ 32 ], + "min_players_per_lineup": [ + 32 + ], "round_restart_delay": [ 32 ], @@ -59595,6 +59637,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], @@ -59690,6 +59735,9 @@ export default { "number_of_substitutes": [ 42 ], + "min_players_per_lineup": [ + 42 + ], "overtime": [ 7 ], @@ -59753,6 +59801,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "round_restart_delay": [ 41 ], @@ -59833,6 +59884,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "overtime": [ 6 ], @@ -59907,6 +59961,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "regions": [ 85 ], @@ -59951,6 +60008,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "regions": [ 3648 ], @@ -59995,6 +60055,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "regions": [ 85 ], @@ -60039,6 +60102,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "regions": [ 3648 ], @@ -60161,6 +60227,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "overtime": [ 3648 ], @@ -60276,6 +60345,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "overtime": [ 6 ], @@ -60329,6 +60401,9 @@ export default { "number_of_substitutes": [ 32 ], + "min_players_per_lineup": [ + 32 + ], "round_restart_delay": [ 32 ], @@ -60358,6 +60433,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], @@ -60387,6 +60465,9 @@ export default { "number_of_substitutes": [ 32 ], + "min_players_per_lineup": [ + 32 + ], "round_restart_delay": [ 32 ], @@ -60416,6 +60497,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], @@ -60445,6 +60529,9 @@ export default { "number_of_substitutes": [ 32 ], + "min_players_per_lineup": [ + 32 + ], "round_restart_delay": [ 32 ], @@ -60474,6 +60561,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], @@ -60556,6 +60646,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "overtime": [ 6 ], @@ -60609,6 +60702,9 @@ export default { "number_of_substitutes": [ 41 ], + "min_players_per_lineup": [ + 41 + ], "round_restart_delay": [ 41 ], @@ -60638,6 +60734,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], @@ -60682,6 +60781,9 @@ export default { "number_of_substitutes": [ 32 ], + "min_players_per_lineup": [ + 32 + ], "round_restart_delay": [ 32 ], @@ -60711,6 +60813,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], @@ -60740,6 +60845,9 @@ export default { "number_of_substitutes": [ 32 ], + "min_players_per_lineup": [ + 32 + ], "round_restart_delay": [ 32 ], @@ -60769,6 +60877,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], @@ -60798,6 +60909,9 @@ export default { "number_of_substitutes": [ 32 ], + "min_players_per_lineup": [ + 32 + ], "round_restart_delay": [ 32 ], @@ -60827,6 +60941,9 @@ export default { "number_of_substitutes": [ 3648 ], + "min_players_per_lineup": [ + 3648 + ], "round_restart_delay": [ 3648 ], diff --git a/hasura/functions/match/check_match_has_min_players.sql b/hasura/functions/match/check_match_has_min_players.sql index 5b484c08a..be41259d9 100644 --- a/hasura/functions/match/check_match_has_min_players.sql +++ b/hasura/functions/match/check_match_has_min_players.sql @@ -5,11 +5,11 @@ DECLARE min_players INTEGER; lineup_1_count INTEGER; lineup_2_count INTEGER; - match_type VARCHAR(255); + options public.match_options; BEGIN - SELECT type INTO match_type - FROM match_options - WHERE id = match.match_options_id; + SELECT mo.* INTO options + FROM match_options mo + WHERE mo.id = match.match_options_id; WITH lineup_counts AS ( SELECT get_lineup_counts(match) AS counts @@ -22,7 +22,7 @@ BEGIN lineup_2_count FROM lineup_counts; - min_players := get_match_type_min_players(match_type); + min_players := get_match_options_min_players(options); IF lineup_1_count < min_players OR lineup_2_count < min_players THEN RETURN false; @@ -30,4 +30,4 @@ BEGIN RETURN true; END; -$$; \ No newline at end of file +$$; diff --git a/hasura/functions/match/get_match_options_min_players.sql b/hasura/functions/match/get_match_options_min_players.sql new file mode 100644 index 000000000..53a213257 --- /dev/null +++ b/hasura/functions/match/get_match_options_min_players.sql @@ -0,0 +1,35 @@ +-- The per-lineup minimum for one match, in precedence order: +-- 1. what the match actually launched at (set when a draft force-started short-handed) +-- 2. the custom game mode's own team size +-- 3. the match type's fixed 5 / 2 / 1 +-- Everything that gates on "enough players" reads this rather than the type, so +-- a custom mode can size a match without touching the closed e_match_types enum. +-- +-- plpgsql, not sql: this file sorts before get_match_type_min_players.sql, and a +-- LANGUAGE sql body is resolved at creation time -- which would fail the very +-- first boot against an empty database. +CREATE OR REPLACE FUNCTION public.get_match_options_min_players(mo public.match_options) +RETURNS integer +LANGUAGE plpgsql +STABLE +AS $$ +DECLARE + mode_players integer; +BEGIN + IF mo.min_players_per_lineup IS NOT NULL THEN + RETURN mo.min_players_per_lineup; + END IF; + + IF mo.game_mode_id IS NOT NULL THEN + SELECT gm.players_per_team INTO mode_players + FROM public.game_modes gm + WHERE gm.id = mo.game_mode_id; + + IF mode_players IS NOT NULL THEN + RETURN mode_players; + END IF; + END IF; + + RETURN public.get_match_type_min_players(mo.type); +END; +$$; diff --git a/hasura/functions/match/lineups/is_match_lineup_ready.sql b/hasura/functions/match/lineups/is_match_lineup_ready.sql index 0820180fa..04bfa9984 100644 --- a/hasura/functions/match/lineups/is_match_lineup_ready.sql +++ b/hasura/functions/match/lineups/is_match_lineup_ready.sql @@ -3,17 +3,19 @@ RETURNS boolean LANGUAGE plpgsql STABLE AS $$ DECLARE - match_type text; + options public.match_options; total_checked_in int; _check_in_setting text; BEGIN - SELECT mo.type, mo.check_in_setting - INTO match_type, _check_in_setting + SELECT mo.* + INTO options FROM matches m INNER JOIN match_options mo ON mo.id = m.match_options_id WHERE m.id = match_lineup.match_id LIMIT 1; + _check_in_setting := options.check_in_setting; + IF _check_in_setting = 'Captains' THEN SELECT count(*) INTO total_checked_in @@ -29,6 +31,6 @@ BEGIN FROM match_lineup_players mlp WHERE mlp.match_lineup_id = match_lineup.id AND mlp.checked_in = true; - RETURN total_checked_in >= get_match_type_min_players(match_type); + RETURN total_checked_in >= get_match_options_min_players(options); END; $$; diff --git a/hasura/functions/match/match_players_per_lineup.sql b/hasura/functions/match/match_players_per_lineup.sql index 0aa36adf3..2c00229ed 100644 --- a/hasura/functions/match/match_players_per_lineup.sql +++ b/hasura/functions/match/match_players_per_lineup.sql @@ -3,7 +3,7 @@ RETURNS integer LANGUAGE sql STABLE AS $$ - SELECT get_match_type_min_players(mo.type) + COALESCE(mo.number_of_substitutes, 0) + SELECT get_match_options_min_players(mo) + COALESCE(mo.number_of_substitutes, 0) FROM match_options mo WHERE mo.id = match.match_options_id; $$; @@ -13,7 +13,7 @@ RETURNS integer LANGUAGE sql STABLE AS $$ - SELECT get_match_type_min_players(mo.type) + SELECT get_match_options_min_players(mo) FROM match_options mo WHERE mo.id = match.match_options_id; $$; @@ -23,7 +23,7 @@ RETURNS integer LANGUAGE sql STABLE AS $$ - SELECT get_match_type_min_players(mo.type) + COALESCE(mo.number_of_substitutes, 0) + SELECT get_match_options_min_players(mo) + COALESCE(mo.number_of_substitutes, 0) FROM match_options mo WHERE mo.id = tournament.match_options_id; $$; @@ -33,7 +33,7 @@ RETURNS integer LANGUAGE sql STABLE AS $$ - SELECT get_match_type_min_players(mo.type) + SELECT get_match_options_min_players(mo) FROM match_options mo WHERE mo.id = tournament.match_options_id; $$; diff --git a/hasura/metadata/actions.graphql b/hasura/metadata/actions.graphql index c489d7cf3..eeeed742d 100644 --- a/hasura/metadata/actions.graphql +++ b/hasura/metadata/actions.graphql @@ -1687,6 +1687,13 @@ type Mutation { ): SuccessOutput } +type Mutation { + startDraftGame( + draftGameId: uuid! + force: Boolean + ): SuccessOutput +} + type Mutation { joinDraftGame( draftGameId: uuid! diff --git a/hasura/metadata/actions.yaml b/hasura/metadata/actions.yaml index a82594ea4..6a75ae528 100644 --- a/hasura/metadata/actions.yaml +++ b/hasura/metadata/actions.yaml @@ -65,6 +65,14 @@ actions: permissions: - role: user comment: updateDraftGame + - name: startDraftGame + definition: + kind: synchronous + handler: '{{HASURA_GRAPHQL_ACTIONS_HOOK}}' + forward_client_headers: true + permissions: + - role: user + comment: startDraftGame - name: joinDraftGame definition: kind: synchronous diff --git a/hasura/metadata/databases/default/tables/public_game_modes.yaml b/hasura/metadata/databases/default/tables/public_game_modes.yaml index d7b2e171a..0861ec018 100644 --- a/hasura/metadata/databases/default/tables/public_game_modes.yaml +++ b/hasura/metadata/databases/default/tables/public_game_modes.yaml @@ -41,6 +41,8 @@ select_permissions: - enabled - archived_at - competitive_safe + - players_per_team + - allow_short_handed_start - cfg - extra_game_params - created_at @@ -62,6 +64,8 @@ select_permissions: - enabled - archived_at - competitive_safe + - players_per_team + - allow_short_handed_start - cfg - extra_game_params - created_at @@ -86,6 +90,8 @@ insert_permissions: - enabled - archived_at - competitive_safe + - players_per_team + - allow_short_handed_start - cfg - extra_game_params computed_fields: @@ -103,6 +109,8 @@ update_permissions: - enabled - archived_at - competitive_safe + - players_per_team + - allow_short_handed_start - cfg - extra_game_params computed_fields: diff --git a/hasura/metadata/databases/default/tables/public_match_options.yaml b/hasura/metadata/databases/default/tables/public_match_options.yaml index a424839a6..407fa0bc6 100644 --- a/hasura/metadata/databases/default/tables/public_match_options.yaml +++ b/hasura/metadata/databases/default/tables/public_match_options.yaml @@ -122,6 +122,8 @@ select_permissions: - match_mode - mr - number_of_substitutes + - min_players_per_lineup + - expected_players - overtime - prefer_dedicated_server - ready_setting diff --git a/hasura/migrations/default/1886000000000_game_mode_player_counts/down.sql b/hasura/migrations/default/1886000000000_game_mode_player_counts/down.sql new file mode 100644 index 000000000..238375981 --- /dev/null +++ b/hasura/migrations/default/1886000000000_game_mode_player_counts/down.sql @@ -0,0 +1,5 @@ +ALTER TABLE "public"."match_options" DROP COLUMN IF EXISTS "min_players_per_lineup"; + +ALTER TABLE "public"."game_modes" DROP CONSTRAINT IF EXISTS "game_modes_players_per_team_check"; +ALTER TABLE "public"."game_modes" DROP COLUMN IF EXISTS "allow_short_handed_start"; +ALTER TABLE "public"."game_modes" DROP COLUMN IF EXISTS "players_per_team"; diff --git a/hasura/migrations/default/1886000000000_game_mode_player_counts/up.sql b/hasura/migrations/default/1886000000000_game_mode_player_counts/up.sql new file mode 100644 index 000000000..f0c2cacc8 --- /dev/null +++ b/hasura/migrations/default/1886000000000_game_mode_player_counts/up.sql @@ -0,0 +1,28 @@ +-- A mode's team size. NULL means "inherit the match type's count", which is what +-- every mode created before this migration does, so nothing changes for them. +-- Capped at 5 because a CS2 team has five slots and match_lineup_players is +-- sized off the same number. +ALTER TABLE "public"."game_modes" + ADD COLUMN IF NOT EXISTS "players_per_team" integer; + +-- Whether a draft lobby running this mode may start before both sides are full. +-- Defaults off so an existing mode can never start short-handed by accident. +ALTER TABLE "public"."game_modes" + ADD COLUMN IF NOT EXISTS "allow_short_handed_start" boolean NOT NULL DEFAULT false; + +DO $$ +BEGIN + ALTER TABLE "public"."game_modes" + ADD CONSTRAINT "game_modes_players_per_team_check" + CHECK ("players_per_team" IS NULL OR "players_per_team" BETWEEN 1 AND 5); +EXCEPTION + WHEN duplicate_object THEN NULL; +END; +$$; + +-- The size a match actually launched at, written only when a lobby force-starts +-- short-handed. Snapshotted rather than resolved live so editing the mode later +-- cannot retroactively invalidate a match that is already running. NULL falls +-- back to the mode, then to the match type. +ALTER TABLE "public"."match_options" + ADD COLUMN IF NOT EXISTS "min_players_per_lineup" integer; diff --git a/hasura/migrations/default/1886000000100_match_options_expected_players/down.sql b/hasura/migrations/default/1886000000100_match_options_expected_players/down.sql new file mode 100644 index 000000000..253f57fe3 --- /dev/null +++ b/hasura/migrations/default/1886000000100_match_options_expected_players/down.sql @@ -0,0 +1 @@ +ALTER TABLE "public"."match_options" DROP COLUMN IF EXISTS "expected_players"; diff --git a/hasura/migrations/default/1886000000100_match_options_expected_players/up.sql b/hasura/migrations/default/1886000000100_match_options_expected_players/up.sql new file mode 100644 index 000000000..ee5a76c6c --- /dev/null +++ b/hasura/migrations/default/1886000000100_match_options_expected_players/up.sql @@ -0,0 +1,13 @@ +-- The total a match actually launched with, across both lineups. +-- +-- Its own migration rather than an edit to 1886000000000, because migrations are +-- tracked by version and never re-read: appending to one that has already been +-- applied is a silent no-op on every database that ran it. +-- +-- Separate from min_players_per_lineup because a single per-lineup number cannot +-- express an uneven start. A 1v2 records 1 there -- the gates apply that to +-- *both* sides, so the smaller one has to clear -- while the game server still +-- has to wait for 3 people. Counts starters only; NULL on every match that did +-- not start short-handed. +ALTER TABLE "public"."match_options" + ADD COLUMN IF NOT EXISTS "expected_players" integer; diff --git a/hasura/triggers/draft_games.sql b/hasura/triggers/draft_games.sql index 4163b0f5e..a434836da 100644 --- a/hasura/triggers/draft_games.sql +++ b/hasura/triggers/draft_games.sql @@ -1,16 +1,26 @@ CREATE OR REPLACE FUNCTION public.tbi_draft_games() RETURNS TRIGGER LANGUAGE plpgsql AS $$ +DECLARE + _mode_capacity integer; BEGIN IF NOT has_available_server_region() THEN RAISE EXCEPTION 'No game server regions are currently available' USING ERRCODE = '22000'; END IF; - NEW.capacity := CASE NEW.type + -- A custom mode can size its own teams; everything else falls back to the + -- match type. match_options is inserted before the draft row, so the mode is + -- already reachable here. + SELECT gm.players_per_team * 2 INTO _mode_capacity + FROM public.match_options mo + INNER JOIN public.game_modes gm ON gm.id = mo.game_mode_id + WHERE mo.id = NEW.match_options_id; + + NEW.capacity := COALESCE(_mode_capacity, CASE NEW.type WHEN 'Duel' THEN 2 WHEN 'Wingman' THEN 4 ELSE 10 - END; + END); IF NEW.mode = 'Teams' AND NEW.team_1_id IS NOT NULL AND NEW.team_2_id IS NOT NULL THEN NEW.access := 'Private'; @@ -33,6 +43,7 @@ DECLARE accepted_count integer; team1 integer; team2 integer; + short_handed boolean; BEGIN IF NEW.expires_at IS DISTINCT FROM OLD.expires_at AND NEW.expires_at IS NOT NULL THEN NEW.expires_at := LEAST(NEW.expires_at, NEW.created_at + interval '120 minutes'); @@ -54,16 +65,39 @@ BEGIN FROM public.draft_game_players WHERE draft_game_id = NEW.id; + -- A custom mode may permit starting before both sides are full. The + -- lobby still has to hold a real match: at least one player a side, and + -- an even pool for Captains, whose pick pattern is built on capacity / 2 + -- and produces a malformed order for an odd number of players. + SELECT COALESCE(gm.allow_short_handed_start, false) INTO short_handed + FROM public.match_options mo + INNER JOIN public.game_modes gm ON gm.id = mo.game_mode_id + WHERE mo.id = NEW.match_options_id; + + short_handed := COALESCE(short_handed, false); + IF NEW.mode = 'Teams' THEN IF NEW.team_1_id IS NULL THEN RAISE EXCEPTION 'Select at least one team first' USING ERRCODE = '22000'; END IF; ELSIF NEW.mode = 'Host' THEN - IF team1 <> NEW.capacity / 2 OR team2 <> NEW.capacity / 2 THEN + IF short_handed THEN + IF team1 < 1 OR team2 < 1 THEN + RAISE EXCEPTION 'Assign at least one player to each team first' USING ERRCODE = '22000'; + END IF; + ELSIF team1 <> NEW.capacity / 2 OR team2 <> NEW.capacity / 2 THEN RAISE EXCEPTION 'Assign all players into balanced teams first' USING ERRCODE = '22000'; END IF; ELSE - IF accepted_count <> NEW.capacity THEN + IF short_handed THEN + IF accepted_count < 2 THEN + RAISE EXCEPTION 'At least two players must accept before starting' USING ERRCODE = '22000'; + END IF; + + IF NEW.mode = 'Captains' AND accepted_count % 2 <> 0 THEN + RAISE EXCEPTION 'A captains draft needs an even number of players' USING ERRCODE = '22000'; + END IF; + ELSIF accepted_count <> NEW.capacity THEN RAISE EXCEPTION 'The lobby must be full to start' USING ERRCODE = '22000'; END IF; END IF; diff --git a/hasura/triggers/match_lineup_players.sql b/hasura/triggers/match_lineup_players.sql index 2194bd5a1..c6b691fad 100644 --- a/hasura/triggers/match_lineup_players.sql +++ b/hasura/triggers/match_lineup_players.sql @@ -42,11 +42,13 @@ LANGUAGE plpgsql AS $$ DECLARE status text; - match_type text; lineup_count INT; _max_players_per_lineup INT; BEGIN - SELECT mo.type, m.status INTO match_type, status + -- Resolved here rather than carrying the match_options row: plpgsql refuses + -- a record variable in a multiple-item INTO list. + SELECT get_match_options_min_players(mo), m.status + INTO _max_players_per_lineup, status FROM matches m INNER JOIN match_lineups ml ON ml.match_id = m.id INNER JOIN match_options mo ON mo.id = m.match_options_id @@ -64,8 +66,6 @@ BEGIN WHERE match_lineup_id = OLD.match_lineup_id; IF ((status != 'PickingPlayers' AND status != 'Canceled') AND (current_setting('hasura.user', true)::jsonb ->> 'x-hasura-role')::text != 'admin') THEN - SELECT get_match_type_min_players(match_type) INTO _max_players_per_lineup; - IF (lineup_count - 1) >= _max_players_per_lineup THEN RETURN OLD; END IF; diff --git a/src/draft-games/draft-game.service.ts b/src/draft-games/draft-game.service.ts index 15b8db876..4619a59fe 100644 --- a/src/draft-games/draft-game.service.ts +++ b/src/draft-games/draft-game.service.ts @@ -15,7 +15,11 @@ import { import { HasuraService } from "src/hasura/hasura.service"; import { NotificationsService } from "../notifications/notifications.service"; import { CacheService } from "src/cache/cache.service"; -import { ExpectedPlayers } from "src/discord-bot/enums/ExpectedPlayers"; +import { + GameModeSizing, + allowsShortHandedStart as modeAllowsShortHandedStart, + resolveCapacity, +} from "src/game-plugins/resolveExpectedPlayers"; import { isRoleAbove } from "src/utilities/isRoleAbove"; import { DraftGame } from "./types/DraftGame"; import { DraftGameError } from "./types/DraftGameError"; @@ -132,7 +136,13 @@ export class DraftGameService { } } - const capacity = ExpectedPlayers[settings.type]; + // A custom mode can size its own teams. The DB trigger derives capacity + // the same way off match_options; this copy is what seeds the lobby with + // the host's party, so the two have to agree. + const gameMode = await this.getGameModeSizing( + this.requestedGameModeId(user, settings.options), + ); + const capacity = resolveCapacity(settings.type, gameMode); const elo = hostJoins ? await this.getPlayerElo(user.steam_id, settings.type) : null; @@ -1049,6 +1059,51 @@ export class DraftGameService { return insert_map_pools_one.id; } + // game_mode_id is gated behind match_organizer in matchOptionScalars, so a + // lower role submitting one must not be allowed to resize the lobby with it. + private requestedGameModeId( + user: User, + options?: Record, + ): string | null { + if (!options || !isRoleAbove(user.role, "match_organizer")) { + return null; + } + + return (options as Record).game_mode_id || null; + } + + // What the mode will be after this settings update: the submitted one when + // the user may set it, otherwise whatever match_options already holds. + private async nextGameModeId( + user: User, + settings: Partial, + draftGame: DraftGame, + ): Promise { + if (settings.options && isRoleAbove(user.role, "match_organizer")) { + return this.requestedGameModeId(user, settings.options); + } + + return this.currentGameModeId(draftGame); + } + + private async getGameModeSizing( + gameModeId?: string | null, + ): Promise { + if (!gameModeId) { + return null; + } + + const { game_modes_by_pk } = await this.hasura.query({ + game_modes_by_pk: { + __args: { id: gameModeId }, + players_per_team: true, + allow_short_handed_start: true, + }, + }); + + return game_modes_by_pk ?? null; + } + private matchOptionScalars( user: User, options: Record, @@ -1177,6 +1232,134 @@ export class DraftGameService { } } + // Flipping the row to Filled is what kicks off beginDraft, and the DB trigger + // refuses that unless the lobby is ready. A short-handed start has to narrow + // the lobby to the players who actually turned up *before* that trigger and + // the draft pick pattern read capacity, which a raw client mutation cannot do. + public async startDraftGame(user: User, draftGameId: string, force: boolean) { + return this.draftLock(draftGameId, async () => { + const draftGame = await this.getDraftGame(draftGameId); + + if (!draftGame) { + throw new DraftGameError("Draft game not found"); + } + + if (!this.isOrganizerOrHost(user, draftGame)) { + throw new DraftGameError( + "Only the host or an organizer can start the match", + ); + } + + if (draftGame.status !== "Open") { + throw new DraftGameError("This draft has already started"); + } + + const accepted = this.acceptedPlayers(draftGame); + const isFull = + draftGame.mode === "Teams" || accepted.length >= draftGame.capacity; + + // Narrowing happens before the status flip, never after: the trigger lets + // a short-handed mode through on the mode alone, so flipping first and + // narrowing second would leave a lobby stuck in Filled that beginDraft + // then refuses to act on -- and every player in it locked out of joining + // anything else. + if (!isFull) { + if (!force) { + throw new DraftGameError("The lobby must be full to start"); + } + + await this.applyShortHandedStart(draftGame, accepted.length); + } + + await this.hasura.mutation({ + update_draft_games_by_pk: { + __args: { + pk_columns: { id: draftGameId }, + _set: { status: "Filled" }, + }, + __typename: true, + }, + }); + }); + } + + // Pug and Captains split whoever accepted across two sides, so the lobby's + // capacity has to come down to that pool or autoSplit and the pick pattern + // still plan around empty seats. Host and Teams place players by hand and are + // left alone -- their sides are already whatever the host made them. + private async applyShortHandedStart( + draftGame: DraftGame, + acceptedCount: number, + ) { + const gameMode = await this.getGameModeSizing( + await this.currentGameModeId(draftGame), + ); + + if (!modeAllowsShortHandedStart(gameMode)) { + throw new DraftGameError("The lobby must be full to start"); + } + + if (draftGame.mode === "Teams" || draftGame.mode === "Host") { + return; + } + + if (acceptedCount < 2) { + throw new DraftGameError( + "At least two players must accept before starting", + ); + } + + // get_draft_game_pattern builds the pick order off capacity / 2, which an + // odd pool turns into a short pattern that strands the last player. + if (draftGame.mode === "Captains" && acceptedCount % 2 !== 0) { + throw new DraftGameError( + "A captains draft needs an even number of players", + ); + } + + if (acceptedCount >= draftGame.capacity) { + return; + } + + await this.hasura.mutation({ + update_draft_games_by_pk: { + __args: { + pk_columns: { id: draftGame.id }, + _set: { capacity: acceptedCount }, + }, + __typename: true, + }, + }); + + draftGame.capacity = acceptedCount; + } + + // Whether this lobby's custom mode lets it start before both sides are full. + public async allowsShortHandedStart(draftGame: DraftGame): Promise { + const gameMode = await this.getGameModeSizing( + await this.currentGameModeId(draftGame), + ); + + return modeAllowsShortHandedStart(gameMode); + } + + private async currentGameModeId( + draftGame: DraftGame, + ): Promise { + if (!draftGame.match_options_id) { + return null; + } + + const { match_options_by_pk } = await this.hasura.query({ + match_options_by_pk: { + __args: { id: draftGame.match_options_id }, + game_mode_id: true, + }, + }); + + return match_options_by_pk?.game_mode_id || null; + } + public async updateDraftSettings( user: User, draftGameId: string, @@ -1211,17 +1394,28 @@ export class DraftGameService { ]); } - let capacity = draftGame.capacity; - if (settings.type && settings.type !== draftGame.type) { - if (!DraftGameService.DRAFTABLE_TYPES.includes(settings.type)) { - throw new DraftGameError("Invalid draft game type"); - } - capacity = ExpectedPlayers[settings.type]; + if ( + settings.type && + settings.type !== draftGame.type && + !DraftGameService.DRAFTABLE_TYPES.includes(settings.type) + ) { + throw new DraftGameError("Invalid draft game type"); } + // Swapping the custom mode resizes the lobby just as swapping the type + // does, so both have to be resolved together -- a 3v3 mode traded for + // Competitive has to grow back to 10 even though the type never moved. + const nextType = settings.type || draftGame.type; + const nextGameMode = await this.getGameModeSizing( + await this.nextGameModeId(user, settings, draftGame), + ); + const capacity = resolveCapacity(nextType, nextGameMode); + const _set: Record = {}; if (settings.type) { _set.type = settings.type; + } + if (capacity !== draftGame.capacity) { _set.capacity = capacity; } if (settings.regions) { diff --git a/src/draft-games/draft-games.controller.ts b/src/draft-games/draft-games.controller.ts index 3f728504e..2140b2f8b 100644 --- a/src/draft-games/draft-games.controller.ts +++ b/src/draft-games/draft-games.controller.ts @@ -72,6 +72,20 @@ export class DraftGamesController { return { success: true }; } + @HasuraAction() + public async startDraftGame(data: { + user: User; + draftGameId: string; + force?: boolean; + }) { + await this.draftGameService.startDraftGame( + data.user, + data.draftGameId, + data.force === true, + ); + return { success: true }; + } + @HasuraAction() public async joinDraftGame(data: { user: User; diff --git a/src/draft-games/draft-match.service.ts b/src/draft-games/draft-match.service.ts index 2ba147a45..5ae773a9c 100644 --- a/src/draft-games/draft-match.service.ts +++ b/src/draft-games/draft-match.service.ts @@ -1,7 +1,7 @@ import { Logger } from "@nestjs/common"; import { forwardRef, Inject, Injectable } from "@nestjs/common"; import { e_map_pool_types_enum } from "generated"; -import { ExpectedPlayers } from "src/discord-bot/enums/ExpectedPlayers"; +import { resolvePlayersPerTeam } from "src/game-plugins/resolveExpectedPlayers"; import { HasuraService } from "src/hasura/hasura.service"; import { CacheService } from "src/cache/cache.service"; import { MatchAssistantService } from "src/matches/match-assistant/match-assistant.service"; @@ -93,6 +93,8 @@ export class DraftMatchService { await this.ensureLineups(draftGame, match); + await this.stampLaunchSize(draftGame, match); + // The room's conversation continues in the match chat: carry the history // over and tear down the draft lobby so non-participants drop out. await this.chat.migrateLobbyMessages( @@ -125,6 +127,81 @@ export class DraftMatchService { await this.matchAssistant.updateMatchStatus(match.id, "WaitingForCheckIn"); } + // A lobby that started short-handed produces a match smaller than its mode + // declares, and every gate downstream -- check_match_has_min_players, + // is_match_lineup_ready, the lineup removal trigger -- would refuse it. Pin + // the size it actually launched at so those read the real shape. + // + // Two numbers, because one cannot express an uneven start: + // + // min_players_per_lineup -- the SMALLER side. The gates apply it to both + // lineups, so a 1v2 has to record 1 or the short side never clears. + // expected_players -- the TOTAL. What the game server waits for. A 1v2 + // records 3; deriving it as min x 2 would give 2 and take the match live + // with someone still connecting. + // + // Both count starters only, read off the draft rather than the match lineups: + // buildTeams also seats waitlisted backups in the substitute slots, and a + // backup is not someone warmup should wait for. + private async stampLaunchSize( + draftGame: DraftGame, + match: { id: string; lineup_1_id?: string | null; lineup_2_id?: string | null }, + ) { + if (!draftGame.match_options_id) { + return; + } + + const { match_options_by_pk } = await this.hasura.query({ + match_options_by_pk: { + __args: { id: draftGame.match_options_id }, + game_mode: { + players_per_team: true, + allow_short_handed_start: true, + }, + }, + }); + + const gameMode = match_options_by_pk?.game_mode; + + if (!gameMode?.allow_short_handed_start) { + return; + } + + const declared = resolvePlayersPerTeam(draftGame.type, gameMode); + + const [side1, side2] = this.starterCounts(draftGame); + const smallest = Math.min(side1, side2); + + if (smallest >= declared) { + return; + } + + await this.hasura.mutation({ + update_match_options_by_pk: { + __args: { + pk_columns: { id: draftGame.match_options_id }, + _set: { + min_players_per_lineup: Math.max(1, smallest), + expected_players: Math.max(2, side1 + side2), + }, + }, + __typename: true, + }, + }); + } + + private starterCounts(draftGame: DraftGame): [number, number] { + const starters = (lineup: number) => + draftGame.players.filter( + (player) => + player.lineup === lineup && + player.status !== "Waitlist" && + player.status !== "Requested", + ).length; + + return [starters(1), starters(2)]; + } + private async ensureLineups( draftGame: DraftGame, match: { lineup_1_id?: string | null; lineup_2_id?: string | null }, @@ -333,19 +410,26 @@ export class DraftMatchService { } private async maxPlayersPerLineup(draftGame: DraftGame): Promise { - const starters = Math.floor(ExpectedPlayers[draftGame.type] / 2); - if (!draftGame.match_options_id) { - return starters; + return resolvePlayersPerTeam(draftGame.type); } const { match_options_by_pk } = await this.hasura.query({ match_options_by_pk: { __args: { id: draftGame.match_options_id }, number_of_substitutes: true, + game_mode: { + players_per_team: true, + allow_short_handed_start: true, + }, }, }); + const starters = resolvePlayersPerTeam( + draftGame.type, + match_options_by_pk?.game_mode, + ); + return starters + (match_options_by_pk?.number_of_substitutes ?? 0); } diff --git a/src/draft-games/draft.service.ts b/src/draft-games/draft.service.ts index d09b23840..fefc5ca04 100644 --- a/src/draft-games/draft.service.ts +++ b/src/draft-games/draft.service.ts @@ -45,6 +45,8 @@ export class DraftService { const perTeam = draftGame.capacity / 2; const accepted = this.draftGameService.acceptedPlayers(draftGame); + const shortHanded = + await this.draftGameService.allowsShortHandedStart(draftGame); if (draftGame.mode === "Teams") { if (!draftGame.team_1_id) { @@ -54,10 +56,13 @@ export class DraftService { return; } + // Only a short-handed lobby relaxes these. It narrows capacity to the + // players who turned up, so an equality could strand a room the trigger + // already cleared; every other lobby keeps the exact == it always had. if (draftGame.mode === "Host") { const team1 = accepted.filter((player) => player.lineup === 1).length; const team2 = accepted.filter((player) => player.lineup === 2).length; - if (team1 !== perTeam || team2 !== perTeam) { + if (shortHanded ? team1 < 1 || team2 < 1 : team1 !== perTeam || team2 !== perTeam) { return; } await this.draftMatchService.finalize(draftGameId); @@ -65,7 +70,11 @@ export class DraftService { } if (draftGame.mode === "Pug") { - if (accepted.length !== draftGame.capacity) { + if ( + shortHanded + ? accepted.length < draftGame.capacity + : accepted.length !== draftGame.capacity + ) { return; } await this.autoSplit(draftGame); @@ -74,7 +83,11 @@ export class DraftService { } if (draftGame.mode === "Captains") { - if (accepted.length !== draftGame.capacity) { + if ( + shortHanded + ? accepted.length < draftGame.capacity + : accepted.length !== draftGame.capacity + ) { return; } await this.runDraftStart(draftGameId); diff --git a/src/game-plugins/game-modes.service.ts b/src/game-plugins/game-modes.service.ts index eceab9590..be381a601 100644 --- a/src/game-plugins/game-modes.service.ts +++ b/src/game-plugins/game-modes.service.ts @@ -9,6 +9,9 @@ export type ResolvedGameMode = { name: string; cfg: string | null; extraGameParams: string | null; + // How many players a side this mode is built for; null means it inherits the + // match type's count. + playersPerTeam: number | null; enabledPlugins: string; pluginConfigs: string | null; missingRequired: Array; @@ -41,6 +44,7 @@ type ModeRow = { name: string; cfg: string | null; extra_game_params: string | null; + players_per_team: number | null; }; type ModePluginRow = { @@ -197,6 +201,8 @@ export class GameModesService { name: "", cfg: null, extraGameParams: null, + // No mode means no size override; the match keeps its type's count. + playersPerTeam: null, enabledPlugins: enabled.join(","), pluginConfigs: null, missingRequired: [], @@ -257,7 +263,7 @@ export class GameModesService { scope?: PluginScope, ): Promise { const [mode] = await this.postgres.query>( - `SELECT id, slug, name, cfg, extra_game_params + `SELECT id, slug, name, cfg, extra_game_params, players_per_team FROM game_modes WHERE id = $1 AND enabled = true AND archived_at IS NULL`, [gameModeId], @@ -328,6 +334,7 @@ export class GameModesService { name: mode.name, cfg: mode.cfg, extraGameParams: mode.extra_game_params, + playersPerTeam: mode.players_per_team ?? null, enabledPlugins: enabled.join(","), pluginConfigs: Object.keys(configs).length > 0 diff --git a/src/game-plugins/resolveExpectedPlayers.ts b/src/game-plugins/resolveExpectedPlayers.ts new file mode 100644 index 000000000..4ccc66591 --- /dev/null +++ b/src/game-plugins/resolveExpectedPlayers.ts @@ -0,0 +1,32 @@ +import { e_match_types_enum } from "generated"; +import { ExpectedPlayers } from "src/discord-bot/enums/ExpectedPlayers"; + +// A custom game mode may declare its own team size. Everything else -- every +// ranked type, and any mode that leaves players_per_team null -- keeps the fixed +// count the match type has always carried. +export interface GameModeSizing { + players_per_team?: number | null; + allow_short_handed_start?: boolean | null; +} + +export function resolvePlayersPerTeam( + type: e_match_types_enum, + gameMode?: GameModeSizing | null, +): number { + if (gameMode?.players_per_team) { + return gameMode.players_per_team; + } + + return ExpectedPlayers[type] / 2; +} + +export function resolveCapacity( + type: e_match_types_enum, + gameMode?: GameModeSizing | null, +): number { + return resolvePlayersPerTeam(type, gameMode) * 2; +} + +export function allowsShortHandedStart(gameMode?: GameModeSizing | null) { + return gameMode?.allow_short_handed_start === true; +} diff --git a/src/matches/events/MatchUpdatedLineupsEvent.ts b/src/matches/events/MatchUpdatedLineupsEvent.ts index d93e1c10c..0ab66cfa4 100644 --- a/src/matches/events/MatchUpdatedLineupsEvent.ts +++ b/src/matches/events/MatchUpdatedLineupsEvent.ts @@ -1,4 +1,4 @@ -import { ExpectedPlayers } from "src/discord-bot/enums/ExpectedPlayers"; +import { resolvePlayersPerTeam } from "src/game-plugins/resolveExpectedPlayers"; import MatchEventProcessor from "./abstracts/MatchEventProcessor"; export default class MatchUpdatedLineupsEvent extends MatchEventProcessor<{ @@ -73,7 +73,14 @@ export default class MatchUpdatedLineupsEvent extends MatchEventProcessor<{ } } - if (players.length < ExpectedPlayers[match.options.type]) { + // A short-handed custom-mode match legitimately reports fewer players than + // the type expects; measuring against the type would throw the whole roster + // away and leave the lineups stale. + const expected = + match.options.min_players_per_lineup ?? + resolvePlayersPerTeam(match.options.type, match.options.game_mode); + + if (players.length < expected * 2) { return; } diff --git a/src/matches/match-assistant/match-assistant.service.ts b/src/matches/match-assistant/match-assistant.service.ts index eb00feb43..4de594e8b 100644 --- a/src/matches/match-assistant/match-assistant.service.ts +++ b/src/matches/match-assistant/match-assistant.service.ts @@ -246,6 +246,11 @@ export class MatchAssistantService { map_veto_picking_lineup_id: true, options: { type: true, + min_players_per_lineup: true, + game_mode: { + players_per_team: true, + allow_short_handed_start: true, + }, }, lineup_1_id: true, lineup_2_id: true, diff --git a/src/matches/matches.controller.ts b/src/matches/matches.controller.ts index 85fe3f18c..6f9c35ed6 100644 --- a/src/matches/matches.controller.ts +++ b/src/matches/matches.controller.ts @@ -230,6 +230,8 @@ export class MatchesController { halftime_pausematch: true, camera_required: true, game_mode_id: true, + min_players_per_lineup: true, + expected_players: true, }, match_maps: { id: true, @@ -460,6 +462,19 @@ export class MatchesController { match.options.cfg_execs.push("mode"); } + // Tells the server this match is not the size its type implies, so the ready + // check, the short-handed auto-pause and the per-team join cap all measure + // against the roster it was actually given. The snapshot wins: a lobby that + // started short-handed is smaller than even its mode declares. Null on a + // normal match, where the plugin keeps its own 5/2/1 table. + match.options.min_players_per_lineup = + match.options.min_players_per_lineup ?? gameMode?.playersPerTeam ?? null; + + // The total to wait for, which min_players_per_lineup cannot express once + // the sides are uneven. Only a short-handed start records one; otherwise the + // server doubles the per-lineup figure as before. + match.options.expected_players = match.options.expected_players ?? null; + // withAlwaysLoad answers with a nameless mode when the only thing to load // is an always-load plugin; that is not a mode the match is playing under. match.options.game_mode = gameMode?.id