baclassic package¶
- class baclassic.Achievement(name: str, icon: TextureHandle, icon_color: tuple[float, float, float], level_name: str, *, award: int, hard_mode_only: bool = False)[source]¶
Bases:
objectRepresents attributes and state for an individual achievement.
- announce_completion(sound: bool = True) None[source]¶
Kick off an announcement for this achievement’s completion.
- create_display(x: float, y: float, delay: float, *, outdelay: float | None = None, color: Sequence[float] | None = None, style: str = 'post_game') list[Actor][source]¶
Create a display for the Achievement.
Shows the Achievement icon, name, and description.
- property description_complete: Lstr¶
Get a babase.Lstr for the Achievement’s description when complete.
- property description_complete_langstr: LangStr¶
The brief description for this achievement once earned.
This is the
LangStrflavor ofdescription_complete; seedisplay_name_langstr.
- property description_full_complete: Lstr¶
Get a babase.Lstr for the Achievement’s full desc. when completed.
- property description_full_complete_langstr: LangStr¶
The full description for this achievement once earned.
This is the
LangStrflavor ofdescription_full_complete; seedisplay_name_langstr.
- property description_full_langstr: LangStr¶
The full description for this achievement.
This is the
LangStrflavor ofdescription_full; seedisplay_name_langstr.
- property description_langstr: LangStr¶
The brief description for this achievement.
This is the
LangStrflavor ofdescription; seedisplay_name_langstr.
- property display_name_langstr: LangStr¶
The localized name for this achievement.
This is the
LangStrflavor ofdisplay_name. It exists only for the transition; once api 9 support ends,display_namereturns this and this property goes away with the removal of api 10.
- get_icon_color(complete: bool) Sequence[float][source]¶
Return the color tint for this Achievement’s icon.
- get_icon_texture(complete: bool) Texture[source]¶
Return the icon texture to display for this achievement
- get_icon_ui_texture(complete: bool) bauiv1.Texture[source]¶
Return the icon texture to display for this achievement
- class baclassic.AchievementSubsystem[source]¶
Bases:
objectSubsystem for achievement handling.
Access the single shared instance of this class at ‘ba.app.ach’.
- achievements_for_coop_level(level_name: str) list[Achievement][source]¶
Given a level name, return achievements available for it.
- award_local_achievement(achname: str) None[source]¶
For non-game-based achievements such as controller-connection.
- display_achievement_banner(achname: str) None[source]¶
Display a completion banner for an achievement.
(internal)
Used for server-driven achievements.
- get_achievement(name: str) Achievement[source]¶
Return an Achievement by name.
- baclassic.CHEST_APPEARANCE_DISPLAY_INFOS: dict[ClassicChestAppearance, ChestAppearanceDisplayInfo] = {ClassicChestAppearance.L2: ChestAppearanceDisplayInfo(texclosed=TextureHandle(_apvernum=807, _name='textures/chest_icon'), texclosedtint=TextureHandle(_apvernum=807, _name='textures/chest_icon_tint'), texopen=TextureHandle(_apvernum=807, _name='textures/chest_open_icon'), texopentint=TextureHandle(_apvernum=807, _name='textures/chest_open_icon_tint'), color=(0.8, 1.0, 0.93), tint=(0.65, 1.0, 0.8), tint2=(0.65, 1.0, 0.8), tint3=(1.0, 1.0, 1.0)), ClassicChestAppearance.L3: ChestAppearanceDisplayInfo(texclosed=TextureHandle(_apvernum=807, _name='textures/chest_icon'), texclosedtint=TextureHandle(_apvernum=807, _name='textures/chest_icon_tint'), texopen=TextureHandle(_apvernum=807, _name='textures/chest_open_icon'), texopentint=TextureHandle(_apvernum=807, _name='textures/chest_open_icon_tint'), color=(0.75, 0.9, 1.3), tint=(0.7, 1, 1.9), tint2=(0.7, 1, 1.9), tint3=(1.0, 1.0, 1.0)), ClassicChestAppearance.L4: ChestAppearanceDisplayInfo(texclosed=TextureHandle(_apvernum=807, _name='textures/chest_icon'), texclosedtint=TextureHandle(_apvernum=807, _name='textures/chest_icon_tint'), texopen=TextureHandle(_apvernum=807, _name='textures/chest_open_icon'), texopentint=TextureHandle(_apvernum=807, _name='textures/chest_open_icon_tint'), color=(0.7, 1.0, 1.4), tint=(1.4, 1.6, 2.0), tint2=(1.4, 1.6, 2.0), tint3=(1.0, 1.0, 1.0)), ClassicChestAppearance.L5: ChestAppearanceDisplayInfo(texclosed=TextureHandle(_apvernum=807, _name='textures/chest_icon'), texclosedtint=TextureHandle(_apvernum=807, _name='textures/chest_icon_tint'), texopen=TextureHandle(_apvernum=807, _name='textures/chest_open_icon'), texopentint=TextureHandle(_apvernum=807, _name='textures/chest_open_icon_tint'), color=(0.75, 0.5, 2.4), tint=(1.0, 0.8, 0.0), tint2=(1.0, 0.8, 0.0), tint3=(1.0, 1.0, 1.0)), ClassicChestAppearance.L6: ChestAppearanceDisplayInfo(texclosed=TextureHandle(_apvernum=807, _name='textures/chest_icon'), texclosedtint=TextureHandle(_apvernum=807, _name='textures/chest_icon_tint'), texopen=TextureHandle(_apvernum=807, _name='textures/chest_open_icon'), texopentint=TextureHandle(_apvernum=807, _name='textures/chest_open_icon_tint'), color=(1.1, 0.8, 0.0), tint=(2, 2, 2), tint2=(2, 2, 2), tint3=(1.0, 1.0, 1.0))}¶
Components for the classic BombSquad experience.
This package/feature-set contains functionality related to the classic BombSquad experience. Note that much legacy BombSquad code is still a bit tangled and thus this feature-set is largely inseperable from
bascenev1andbauiv1. Future feature-sets will be designed in a more modular way.
- baclassic.CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT: baclassic._chest.ChestAppearanceDisplayInfo = ChestAppearanceDisplayInfo(texclosed=TextureHandle(_apvernum=807, _name='textures/chest_icon'), texclosedtint=TextureHandle(_apvernum=807, _name='textures/chest_icon_tint'), texopen=TextureHandle(_apvernum=807, _name='textures/chest_open_icon'), texopentint=TextureHandle(_apvernum=807, _name='textures/chest_open_icon_tint'), color=(1, 1, 1), tint=(1, 1, 1), tint2=(1, 1, 1), tint3=(1.0, 1.0, 1.0))¶
Fallback
ChestAppearanceDisplayInfoused when a chest’s declared appearance has no entry inCHEST_APPEARANCE_DISPLAY_INFOS.
- class baclassic.ChestAppearanceDisplayInfo(texclosed: bascenev1.TextureHandle, texclosedtint: bascenev1.TextureHandle, texopen: bascenev1.TextureHandle, texopentint: bascenev1.TextureHandle, color: tuple[float, float, float], tint: tuple[float, float, float], tint2: tuple[float, float, float], tint3: tuple[float, float, float] = (1.0, 1.0, 1.0))[source]¶
Bases:
objectInfo about how to locally display chest appearances.
- texclosed: bascenev1.TextureHandle¶
- texclosedtint: bascenev1.TextureHandle¶
- texopen: bascenev1.TextureHandle¶
- texopentint: bascenev1.TextureHandle¶
- class baclassic.ClassicAppMode[source]¶
Bases:
AppModeAppMode for the classic BombSquad experience.
- classmethod can_handle_intent(intent: AppIntent) bool[source]¶
Override this to define indent handling for an app-mode.
- get_dev_console_ui_debug_draw_toggles() list[DevConsoleToggleDef][source]¶
Define debug-drawing toggles to show up in the UI dev console.
These join the tab’s own in its ‘Debug Drawing’ row (in the console’s expanded view). For ui that the tab itself can’t know about, such as a ui package’s layout guides.
- get_dev_console_ui_tab_buttons() list[DevConsoleButtonDef][source]¶
Define buttons to show up in the UI dev console.
This can be useful for exposing UI code examples or debugging functionality.
- new_app_mode_config() AppModeConfig[source]¶
Create a fresh config describing how this mode should run.
Called by the framework each time this mode is about to become the active one. Override to return your mode’s own
AppModeConfigsubclass, built with the mode’s defaults; the framework then offers it to plugins and passes the final result toon_activate().A fresh instance is built per activation, so nothing can persist between modes (or activations) by construction.
- on_activate(config: AppModeConfig) None[source]¶
Called when the mode is becoming the active one for the app.
configis the object created bynew_app_mode_config()for this activation, possibly amended by plugins. Modes that define their own config type should begin withassert isinstance(config, TheirConfig)to recover the concrete type, then set themselves (and any app-subsystems they use) up from it.
- on_app_active_changed() None[source]¶
Called when the app’s active state changes while in this app-mode.
This corresponds to the app’s
activeattr. App-active state becomes false when the app is hidden, minimized, backgrounded, etc. The app-mode may want to take action such as pausing a running game or saving state when this occurs.On platforms such as mobile where apps get suspended and later silently terminated by the OS, this is likely to be the last reliable place to save state/etc.
To best cover both mobile and desktop style platforms, actions such as saving state should generally happen in response to both
on_deactivate()andon_app_active_changed()(when active is False).
- on_control_permission_request(request: ControlPermissionRequest, on_result: Callable[[ControlPermission], None]) None[source]¶
Ask the user whether something may control the app.
‘Control’ is deliberately broad: running commands, reading this app’s log, and whatever that grows into. Answer via
on_result, which may be called later (from a dialog) or immediately (from policy).The default answers
CANNOT_ASK, which is the honest answer for a mode with no way to prompt – the request is then held and re-put once a mode that can ask activates. An app-mode with a UI should override this; one running without a user present (a dedicated server) should answerALLOW, since nobody is there to ask and the operator already owns the account.
- on_deactivate() None[source]¶
Called when the mode stops being the active one for the app.
On platforms where the app is explicitly exited (such as desktop PC) this will also be called at app shutdown.
To best cover both mobile and desktop style platforms, actions such as saving state should generally happen in response to both
on_deactivate()andon_app_active_changed()(when active is False).
- on_engine_did_reset() None[source]¶
Called just after classic resets the engine.
This happens at various times such as session switches.
- class baclassic.ClassicAppModeConfig[source]¶
Bases:
AppModeConfigDescribes how a
ClassicAppModeshould run.Built fresh (with classic’s defaults) for each activation via
ClassicAppMode.new_app_mode_config(); amend attrs here – from a mode subclass’s override of that method or a plugin’son_app_mode_config()– to alter how the mode sets itself up.- base_assets¶
The classic-flavored art baked into base’s own draw paths (debris, smoke, VR hands, reflections; see
babase.BaseAssetSet). Starts at classic’s real art; reassign any slot to restyle.
- scene_assets¶
The art the scene_v1 node layer draws itself with (see
bascenev1.SceneV1AssetSet). Every slot starts at scene_v1’s own art; reassign any to restyle.
- ui_assets¶
The art the ui layer will be drawn with (see
bauiv1.UIAssetSet). Starts out as classic’s standard look; reassign any slot to restyle.
- class baclassic.ClassicAppSubsystem[source]¶
Bases:
AppSubsystemSubsystem for classic bombsquad functionality in the app.
The single shared instance of this app can be accessed at babase.app.classic. Note that it is possible for babase.app.classic to be None if the classic package is not present, and futureproof code should handle that case gracefully.
- class MusicPlayMode(*values)¶
Bases:
EnumInfluences behavior when playing music.
- REGULAR = 'regular'¶
- TEST = 'test'¶
- class V2AuthData(account_id: str, account_tag: str, player_profiles: dict, classic_purchases: list[str] | None, cloud_characters: list[str] | None, expire_time: float)[source]¶
Bases:
objectAuthenticated data we store for accepted clients.
- classic_purchases: list[str] | None¶
List of classic-inventory purchase legacy-ids owned by the connecting account, or
Nonewhen the master server didn’t provide one (unknown — fall back to the legacy hacky character-list path).
- cloud_characters: list[str] | None¶
The account’s cloud profiles, each as one cloud-composed character json (name + icon + spaz), or
Nonewhen the master server didn’t provide them (older master or unknown) — in which case the lobby falls back to the legacyplayer_profileswith the legacy-profile warning.
- class V2AuthRequest(account_id: str, account_tag: str, account_create_time: datetime.datetime, account_total_active_days: int, app_instance_signature: str, address_signature: str, device_signature: str, classic_purchases: list[str] | None = None)[source]¶
Bases:
objectWhat is passed in to V2 auth handler.
- account_create_time: datetime.datetime¶
When the connecting account was created.
- address_signature: str¶
An abstract value generated from the connecting client’s ip address. Can be used to identify repeat connection attempts/etc.
- app_instance_signature: str¶
An abstract value generated from the connecting client’s app-instance-id. Can be used to identify repeat connection attempts/etc. Note that this value changes each time the client re-launches the app.
- classic_purchases: list[str] | None = None¶
List of classic-inventory purchase legacy-ids owned by the connecting account (e.g.
'characters.kronk').Nonewhen the master server isn’t able to determine this — for example on older master-server versions or when the account has no classic-inventory record. Custom handlers should treatNoneas “unknown” and not as “owns nothing”.
- class V2AuthResponse(allow: bool, error_message: str | None = None)[source]¶
Bases:
objectWhat a V2 auth handler returns.
- account_name_depiction¶
The signed-in account’s name as the cloud composes it, a
bacommon.depiction.NameDepictionas json fed live by the cloud (empty when signed out or not known yet). Pass it as an image or button widget’sdepictionto show the name.
- add_coop_practice_level(level: Level) None[source]¶
Adds an individual level to the ‘practice’ section in Co-op.
- character_preview¶
Shows characters at the master server’s request (someone trying one they are building; see
_characterpreview).
- cloud_profiles¶
The primary account’s cloud profiles (synced + cached).
- create_in_game_tournament_prize_image(entry: dict[str, Any], index: int, position: tuple[float, float]) None[source]¶
Given a tournament entry, return strings for its prize levels.
- async default_v2_auth_handler(request: V2AuthRequest) V2AuthResponse[source]¶
Default auth handler function. Just allows everyone.
- get_input_device_config(inputdevice: InputDevice, default: bool) tuple[dict, str][source]¶
Given an input device, return its config dict in the app config.
The dict will be created if it does not exist.
- get_input_device_map_hash(inputdevice: InputDevice) str[source]¶
Given an input device, return hash based on its raw input values.
- get_input_device_mapped_value(device: InputDevice, name: str, default: bool = False) Any[source]¶
Return a mapped value for an input device.
This checks the user config and falls back to default values where available.
- get_player_profile_colors(profilename: str | None, profiles: dict[str, dict[str, Any]] | None = None) tuple[tuple[float, float, float], tuple[float, float, float]][source]¶
Given a profile, return colors for them.
- get_player_profile_icon(profilename: str) str[source]¶
Given a profile name, returns an icon string for it.
(non-account profiles only)
- get_tournament_prize_strings(entry: dict[str, Any], include_tickets: bool) list[str][source]¶
Given a tournament entry, return strings for its prize levels.
- getmaps(playtype: str) list[str][source]¶
Return a list of bascenev1.Map types supporting a playtype str.
Maps supporting a given playtype must provide a particular set of features and lend themselves to a certain style of play.
Play Types:
- ‘melee’
General fighting map. Has one or more ‘spawn’ locations.
- ‘team_flag’
For games such as Capture The Flag where each team spawns by a flag. Has two or more ‘spawn’ locations, each with a corresponding ‘flag’ location (based on index).
- ‘single_flag’
For games such as King of the Hill or Keep Away where multiple teams are fighting over a single flag. Has two or more ‘spawn’ locations and 1 ‘flag_default’ location.
- ‘conquest’
For games such as Conquest where flags are spread throughout the map - has 2+ ‘flag’ locations, 2+ ‘spawn_by_flag’ locations.
- ‘king_of_the_hill’ - has 2+ ‘spawn’ locations,
1+ ‘flag_default’ locations, and 1+ ‘powerup_spawn’ locations
- ‘hockey’
For hockey games. Has two ‘goal’ locations, corresponding ‘spawn’ locations, and one ‘flag_default’ location (for where puck spawns)
- ‘football’
For football games. Has two ‘goal’ locations, corresponding ‘spawn’ locations, and one ‘flag_default’ location (for where flag/ball/etc. spawns)
- ‘race’
For racing games where players much touch each region in order. Has two or more ‘race_point’ locations.
- host_ui¶
The buttons, pages and party notices a host gives its clients (and shows itself).
Bring up main menu ui.
- launch_coop_game(game: str, force: bool = False, args: dict | None = None) bool[source]¶
High level way to launch a local co-op session.
- on_app_loading() None[source]¶
Called when the app reaches the
LOADINGstate.Note that subsystems created after the app switches to the loading state will not receive this callback. Subsystems created by plugins are an example of this.
- on_app_shutdown() None[source]¶
Called when the app enters the
SHUTTING_DOWNstate.
- pause() None[source]¶
Pause the game due to a user request or menu popping up.
If there’s a foreground host-activity that says it’s pausable, tell it to pause. Note: we now no longer pause if there are connected clients.
- profile_browser_window(transition: str = 'in_right', origin_widget: Widget | None = None) None[source]¶
Pop up a browser window from within a game.
- required_purchases_for_game(game: str) list[str][source]¶
Return which purchase (if any) is required for a game.
- resume() None[source]¶
Resume the game due to a user request or menu closing.
If there’s a foreground host-activity that’s currently paused, tell it to resume.
Attempt to cleanly get back to the main menu.
- run_stress_test(*, playlist_type: str = 'Random', playlist_name: str = '__default__', player_count: int = 8, round_duration: int = 30, attract_mode: bool = False, randomize: bool = True, churn: bool = True) None[source]¶
Run a stress test.
With
randomizeFalse the playlist plays in listed order; withchurnFalse all fake players join at once and stay (both for repeatable performance A/B measurements).
- set_tournament_prize_image(entry: dict[str, Any], index: int, image: Widget) None[source]¶
Given a tournament entry, return strings for its prize levels.
- property subplatform: str¶
String for subplatform.
Can be empty. For the ‘android’ platform, subplatform may be ‘google’, ‘amazon’, etc.
- v2_auth_handler: Callable[[ClassicAppSubsystem.V2AuthRequest], Awaitable[ClassicAppSubsystem.V2AuthResponse]]¶
V2 authentication handler.
To customize who is allowed in your server, assign your own custom handler function to this attribute. This will be called for all connecting clients before they are allowed in the game. Note that protocol must be set to 36 or newer and authenticate_clients must be enabled. For servers you can set those values in the server config.
- class baclassic.ClientEffectContext(targets: EffectTargets | None = None)[source]¶
Bases:
objectWhat client-effects are running alongside, if anything.
Effects that need a context (animating things, say) do nothing without the relevant piece.
- targets: EffectTargets | None = None¶
Targets for
bacommon.clienteffect.KeyframeAnimation.
- class baclassic.EffectTarget(*args, **kwargs)[source]¶
Bases:
ProtocolSomething client-effects can animate.
Implemented by whatever UI system the effects run alongside (a doc-ui window’s widgets, say); effects know nothing about it beyond this.
- class baclassic.EffectTargets(*args, **kwargs)[source]¶
Bases:
ProtocolA set of animatable targets client-effects can look up by id.
- get_target(target_id: str) EffectTarget | None[source]¶
Return the target for an id, if there is a live one.
- class baclassic.HostUIButton(label: str | babase.LangStr | LangStrSpec, route: DocUIRoute, placement: Literal['in_game_menu', 'party_menu'] = 'in_game_menu', layout: bacommon.docui.v2.WindowLayout = WindowLayout.WIDE_TALL)[source]¶
Bases:
objectA button a host puts on its clients’ (and its own) ui.
Pressing it opens the page for
routein a doc-ui window, which the host’sHostUIHandlerserves.- label: str | babase.LangStr | LangStrSpec¶
The label. Plain text is shown as-is; a language-string must come from one of the host’s own asset-packages (clients refuse anything else).
- layout: bacommon.docui.v2.WindowLayout = 'wt'¶
The window layout to open the page in. Wide and tall by default, since host pages often list everyone in the party.
- placement: Literal['in_game_menu', 'party_menu'] = 'in_game_menu'¶
Where the button goes.
- route: DocUIRoute¶
The page the button opens.
- class baclassic.HostUIHandler[source]¶
Bases:
objectServes the doc-ui pages a host’s buttons open.
Adding your own pages takes three pieces: routes naming the pages, a handler serving them, and buttons opening them. A complete plugin-sized example:
from dataclasses import dataclass from efro.dataclassio import ioprepped from bacommon.docui.routes import DocUIRoute, family_members import bacommon.docui.v2 as dui2 from bacommon.langstr import LangStrSpecValue import babase import baclassic # 1. Routes: one family class, one dataclass per page (fields # are the page's args). class MyRoute(DocUIRoute): @classmethod def get_route_types(cls) -> tuple[type[DocUIRoute], ...]: return family_members(AnyMyRoute) @ioprepped @dataclass class Rules(MyRoute, path='/myplugin/rules'): pass AnyMyRoute = Rules # 2. A handler serving them (everything else goes to super()). class MyHandler(baclassic.HostUIHandler): def fulfill_request(self, request, client_id): try: route = MyRoute.from_request(request) except Exception: return super().fulfill_request(request, client_id) assert isinstance(route, Rules) lit = LangStrSpecValue.literal return dui2.Response( page=dui2.Page( title=lit('Rules'), rows=[ dui2.ButtonRow( title=lit('Be nice.'), buttons=[ dui2.Button( label=lit('Ok'), action=dui2.Local(close_window=True), ) ], ) ], ) ) # 3. Plug in: the handler, plus a button opening the page # (alongside the default ones). host_ui = babase.app.classic.host_ui host_ui.handler = MyHandler() host_ui.set_buttons( host_ui.get_buttons() + [baclassic.HostUIButton(label='Rules', route=Rules())] )
To change the default stats page rather than add one, see
baclassic.HostUIStatsPage. If something goes wrong building a page (an exception, or returning something that isn’t a response), the error is logged here and the client gets its standard error page.Keeping pages cheap.
fulfill_request()runs in the logic thread, the one the game itself runs in, so time spent there is time the game stands still. A page built from a handful of values costs next to nothing, and that’s the common case. A page that grows (big tables, sorting or filtering many records, file or network access) should do the heavy part elsewhere:Make
fulfill_request()async.Gather what you need from the game first, on the logic thread (game objects such as players and activities may only be touched there), into plain values.
Build the page from those values in a background thread with
await self.run_in_bg(build_page, values). That function must not touch game objects or ui.
Handlers that spend more than about 10 ms on the logic thread get a warning saying so. (Turning the page into wire data and compressing it already happens in the background.)
- fulfill_request(request: bacommon.docui.v2.Request, client_id: int) bacommon.docui.v2.Response | Awaitable[bacommon.docui.v2.Response][source]¶
Return the page for a request from a client.
client_idis -1 for the host’s own requests. Runs in the logic thread, so game state can be read freely; return an awaitable (or make thisasync) to answer asynchronously. Remember that requests come from clients and are untrusted input.
- async run_in_bg(call: Callable[[], T]) T[source]¶
Run a call in a background thread; return its result.
For the heavy parts of building a page (see the class docs).
callmust not touch game objects or ui; hand it plain values gathered beforehand (functools.partialor a lambda does that nicely). Time spent here doesn’t count toward the slow-handler warning.
- class baclassic.HostUIKickVote(target_client_id: int, target_name: str, starter_client_id: int, end_time: float, votes: dict[int, bool]=<factory>)[source]¶
Bases:
objectA kick vote in progress.
- class baclassic.HostUIKickVotes[source]¶
Bases:
objectThe standard kick vote, run by classic hosts.
Lives at
app.classic.host_ui.kick_votes. Clients pick someone in their party window and choose to kick them, which opens this vote’s page. There they can start a vote; everyone else (who can see host pages: build 23067 and up) gets a ‘Kick X?’ notice with the party icon and ‘…’ button flashing, and votes on the page the ‘…’ menu leads to. Admins (seehost_ui.admins) and the host kick without a vote and can’t be kicked.Customizing. The methods come in sections, in this order:
The rules – every number and decision (vote length, minimum voters, votes required, cooldowns, ban time, who’s an admin, who votes, why a vote can’t start).
What people see – every bit of text; return your own (plain strings are fine) to reword anything.
Running votes – the machinery that applies the rules.
The page – the vote’s doc-ui page.
Subclass this, copy in just the methods you want to change (those in the first two sections use only public api), and assign an instance to
host_ui.kick_votes; for example, for longer votes:class MyKickVotes(baclassic.HostUIKickVotes): def get_vote_duration(self) -> float: return 60.0 babase.app.classic.host_ui.kick_votes = MyKickVotes()
To replace kick votes with something else entirely, turn this off (
set_enabled(), or the server config’senable_default_kick_voting) and pointbaclassic.HostUISubsystem.set_kick_route()at a page of your own.The vote’s notice uses the single party notice clients have; the most recently posted notice wins, so a notice posted during a vote replaces the vote’s (and the vote’s ending replaces whatever is showing then).
Votes starting and ending, and kicks, are logged (
ba.net, at info level); a kick that fails is a warning.- build_page(client_id: int, target_client_id: int | None) Response[source]¶
The vote’s page, for one client.
target_client_idis who they chose to kick, if they came here to kick someone. Refreshes itself every second. Its text comes from the methods above; the layout is engine machinery, so override those rather than this.
- cast_vote(client_id: int, yes: bool) None[source]¶
Record a vote (ignored if there’s no vote or they voted).
- end_vote(passed: bool, quiet: bool = False) None[source]¶
End the vote in progress, kicking its target if it passed.
quietends it without telling anyone how it went (the target left, say).
- get_buttons(client_id: int) list[HostUIButton][source]¶
Buttons a client gets from us (on top of the host’s own).
While a vote runs, a button to its page in everyone’s party menu.
- get_failed_vote_delay(starter: bool) float[source]¶
Seconds before someone can start a vote after one fails.
starteris whether they started the failed one.
- get_host_ui() HostUISubsystem[source]¶
The host-ui subsystem we run on (
app.classic.host_ui).
- get_kick_route(client_id: int) DocUIRoute[source]¶
The page clients get when they choose to kick someone.
- get_kicked_text(name: str) str | LangStr[source]¶
The screen message everyone gets when someone is kicked.
- get_minimum_clients() int[source]¶
Fewest voting clients (not counting the host) for a vote.
A host that is also playing doesn’t count, so require one more then (two of three clients in a 2-on-2 shouldn’t be able to kick the third).
- get_question_text(name: str) str | LangStr[source]¶
‘Kick X?’: the voters’ notice, and the page’s question.
- get_refusal(starter_client_id: int, target_client_id: int) KickVoteRefusal | None[source]¶
Why a client can’t start a vote to kick another (None: they can).
Admins (and the host) skip this; they kick outright.
- get_refusal_text(refusal: KickVoteRefusal, starter_client_id: int) str | LangStr[source]¶
Why a vote can’t start, as told to whoever tried.
- get_start_wait(client_id: int) float[source]¶
Seconds until a client may start a vote (0 if they may now).
- get_time_left_text(ends: datetime) str | LangStr[source]¶
The countdown under the vote’s buttons.
endsis when the vote runs out; clients count down to it live. (Passing adatetimeto a string’s duration param does that; seebacommon.langstr.LangStrSpecTimeTarget.)
- get_voters() list[int][source]¶
Who votes: clients that can see host pages, plus a playing host.
(Clients too old for host pages can’t take part at all.)
- get_votes_needed_text(count: int) str | LangStr[source]¶
The tally: how many more yes votes are needed.
- get_votes_required(client_count: int) int[source]¶
Yes votes needed to kick, given the voting clients present.
client_countdoesn’t include the host; a host that is also playing counts as one more participant (and votes too).
- kick(client_id: int, name: str | None = None) None[source]¶
Kick a client (banning them for
get_ban_time()).
- set_enabled(enabled: bool) None[source]¶
Turn kick voting on or off.
Also offers (or stops offering) this vote’s page as where clients go to kick someone (see
baclassic.HostUISubsystem.set_kick_route()).
- start_vote(starter_client_id: int, target_client_id: int) KickVoteRefusal | None[source]¶
Start a vote (or, for admins, just kick).
Returns why it couldn’t be started, if it couldn’t.
- update() None[source]¶
Check the vote in progress: end it if it passed or failed.
Runs whenever a vote is cast, and every second.
- vote: HostUIKickVote | None¶
The vote in progress, if any.
- class baclassic.HostUIStatsColumn(title: str | babase.LangStr, width: float, value: Callable[[bascenev1.SessionPlayer, HostUIStatsContext], str | babase.LangStr | bacommon.depiction.Depiction | None], hide_when_empty: bool = False)[source]¶
Bases:
objectOne column of values in the stats table, right of the player.
- hide_when_empty: bool = False¶
Leave the column out when nobody has a value for it (rather than showing a column of dashes).
- title: str | babase.LangStr¶
The column’s title. A language-string must come from one of the host’s own asset-packages (clients refuse anything else).
- value: Callable[[bascenev1.SessionPlayer, HostUIStatsContext], str | babase.LangStr | bacommon.depiction.Depiction | None]¶
A player’s value – text, a language-string (each client shows it in its own language), a depiction, or None for none (drawn as a dash). Called on the logic thread for every player each time the page is built, so keep it cheap.
- class baclassic.HostUIStatsContext(account_ids: dict[int, str], records: dict[int, PlayerRecord])[source]¶
Bases:
objectWhat stats column values may need beyond the player itself.
Gathered once per page, so columns can look things up cheaply.
- account_ids: dict[int, str]¶
Verified account ids by client id (-1 being the host’s own); see
bascenev1.get_game_roster().
- record(player: SessionPlayer) PlayerRecord | None[source]¶
A player’s stats record, if they have one.
Records’
accum*values are the current game’s (despite the name; they reset as each game starts) and are what score screens show; the plain ones run for the whole series.
- records: dict[int, PlayerRecord]¶
The session’s stats records (what between-round score screens show), by their players’ ids; see
record().
- class baclassic.HostUIStatsPage[source]¶
Bases:
objectThe stats page classic hosts serve: a table of the party.
One row per player who has joined (icon and name, then a value per column), in scoreboard order during games. Serve your own variation by subclassing this, overriding
get_columns()(or anything else), and assigning an instance toapp.classic.host_ui.stats_page; for example, to add a column:class MyStatsPage(baclassic.HostUIStatsPage): def get_columns(self) -> list[baclassic.HostUIStatsColumn]: return super().get_columns() + [ baclassic.HostUIStatsColumn( 'Streak', 70.0, self.streak_value ) ] def streak_value(self, player, context): rec = context.record(player) return None if rec is None else str(rec.streak) babase.app.classic.host_ui.stats_page = MyStatsPage()
Subclass rather than copy the whole class: copy in just the methods you want to change. Those hold only the decisions (title, refresh rate, columns, which players and in what order, cell values) and use only public api, while the default columns’ localized titles, the table layout and wire details stay in the engine, so they keep working as it updates. A table under a route of your own works the same way: subclass this, and return
self.build(route)from yourbaclassic.HostUIHandler. Pages are built on the logic thread; seebaclassic.HostUIHandlerfor keeping big ones cheap.- account_column() HostUIStatsColumn[source]¶
The default Account column (hidden when nobody has one).
- account_value(player: bascenev1.SessionPlayer, context: HostUIStatsContext) bacommon.depiction.Depiction | None[source]¶
A player’s verified account, as its name depiction.
Known for the host’s own account and for clients that joined with v2 auth; so with client auth off, usually None.
- build(route: DocUIRoute) bacommon.docui.v2.Response[source]¶
Build the page;
routeis the one being served.(It is what the page refreshes itself with.) Gathers players and values through the methods above and lays out the table; the layout is engine machinery, so override those rather than this.
- deaths_column() HostUIStatsColumn[source]¶
The default Deaths column.
- deaths_value(player: SessionPlayer, context: HostUIStatsContext) str | None[source]¶
A player’s deaths this game.
- get_columns() list[HostUIStatsColumn][source]¶
The table’s columns, left to right (after the player’s).
- get_players(session: Session) list[SessionPlayer][source]¶
The players to list (before sorting).
By default everyone who has joined; players still choosing a profile in the lobby have no name or look yet.
- get_refresh_interval() float | None[source]¶
How often (seconds) the page refreshes while open (None: never).
- kills_column() HostUIStatsColumn[source]¶
The default Kills column.
- kills_value(player: SessionPlayer, context: HostUIStatsContext) str | None[source]¶
A player’s kills this game.
- ping_column() HostUIStatsColumn[source]¶
The default Ping column.
- ping_value(player: SessionPlayer, context: HostUIStatsContext) str | None[source]¶
A player’s connection’s ping in ms (as the host measures it).
- score_column() HostUIStatsColumn[source]¶
The default Score column.
- score_value(player: SessionPlayer, context: HostUIStatsContext) str | None[source]¶
A player’s score this game (as score screens show it).
- sort_players(players: list[SessionPlayer], context: HostUIStatsContext, session: Session) list[SessionPlayer][source]¶
Players in the order to list them.
By default scoreboard order during a game: grouped by team in team games, then by score (highest first), ties going to more kills and then fewer deaths, players without stats yet last. Outside a game (nobody has stats), join order.
- class baclassic.HostUISubsystem[source]¶
Bases:
objectHost-defined ui, from both ends.
Access the single shared instance of this class via
app.classic.host_ui.As a host: set the buttons everyone gets with
set_buttons()(or one client’s withset_client_buttons()), post notices withpost_notice(), flash things withflash_party_icon()andflash_party_menu(), and serve pages by assigninghandler. Clients are kept up to date automatically, joiners included.As a client, this holds what our host has declared to us.
- admins: set[str]¶
V2 account ids (a-XXX) of this host’s admins. Admins can’t be kicked by vote, and kick without one.
- clear_notice(*, clients: Sequence[int] | None = None) None[source]¶
Take down the notice (for some clients, or everyone).
- client_has_host_ui(client_id: int) bool[source]¶
Whether a client can see host buttons, notices, and pages.
(Clients predating them can’t.) True for the host (-1) while it has ui.
- flash_party_icon(duration: float, *, clients: Sequence[int] | None = None) None[source]¶
Flash the party icon for a while (0 to stop).
Flash the party window’s ‘…’ button for a while (0 to stop).
- get_account_name_depiction(account_id: str) bacommon.depiction.Depiction | None[source]¶
An account’s name as it draws in game, if we know it.
Known for our own account, and for clients that joined with v2 auth (so it is verified by the master server); see
get_game_roster()for each client’s account id. None otherwise.
- get_buttons() list[HostUIButton][source]¶
The buttons every client gets (unless overridden per client).
- get_client_account_id(client_id: int) str | None[source]¶
A client’s verified v2 account id (a-XXX), if it has one.
- get_client_name(client_id: int) str | None[source]¶
A client’s name as the party list shows it (None if not here).
- handler: HostUIHandler¶
Serves the pages host buttons open.
- kick_votes: HostUIKickVotes¶
The standard kick vote (assign a subclass to customize it).
- post_notice(text: str | LangStr | LangStrSpec, duration: float, *, clients: Sequence[int] | None = None) None[source]¶
Show a notice below the party icon for a while.
Replaces any notice showing (the most recently posted notice wins).
clientslimits it to some clients (-1 is the host); None means everyone. A language-string must come from one of the host’s own asset-packages.
- refresh_clients() None[source]¶
Send everyone their current state again.
For when something the state is built from changed without going through this class (such as the buttons
baclassic.HostUIKickVotes.get_buttons()adds).
- set_buttons(buttons: Sequence[HostUIButton]) None[source]¶
Set the buttons every client gets.
Clients with their own (see
set_client_buttons()) keep theirs.
- set_client_buttons(client_id: int, buttons: Sequence[HostUIButton] | None) None[source]¶
Give one client its own set of buttons (None to undo).
Use -1 for the host’s own ui. Forgotten when the client leaves.
- set_kick_route(get_route: Callable[[int], DocUIRoute] | None) None[source]¶
Set where clients go when they choose to kick someone.
get_routeis called with a client id and returns the page for kicking them (which yourhandlerserves); clients offer kicking on party members only while one is set. None stops offering it. By default the standard kick vote’s page (seebaclassic.HostUIKickVotes).
- stats_page: HostUIStatsPage¶
The default stats page (assign a subclass to customize it).
- class baclassic.KickVoteRefusal(*values)[source]¶
Bases:
EnumWhy a kick vote can’t be started.
- ADMIN = 'admin'¶
The host and admins can’t be kicked.
- COOLDOWN = 'cooldown'¶
The starter has to wait a while (they just joined, or a vote just failed).
- DISABLED = 'disabled'¶
Kick voting is turned off.
- IN_PROGRESS = 'in_progress'¶
A vote is already running.
- NOT_ENOUGH_PLAYERS = 'not_enough_players'¶
Too few voters for a vote to mean anything.
- NOT_PRESENT = 'not_present'¶
The player isn’t here (anymore).
- SELF = 'self'¶
Nobody can kick themselves.
- class baclassic.MusicPlayer[source]¶
Bases:
objectWrangles soundtrack music playback.
Music can be played either through the game itself or via a platform-specific external player.
- on_select_entry(callback: Callable[[Any], None], current_entry: Any, selection_target_name: str) bauiv1.MainWindow[source]¶
Present a GUI to select an entry.
The callback should be called with a valid entry or None to signify that the default soundtrack should be used..
- select_entry(callback: Callable[[Any], None], current_entry: Any, selection_target_name: str) bauiv1.MainWindow[source]¶
Summons a UI to select a new soundtrack entry.
- baclassic.reload_hooks() None[source]¶
Reload functions and other objects held by the native layer. Call this if you replace things in a hooks module to get the native layer to see your changes.
Submodules¶
baclassic.macmusicapp module¶
Music playback functionality using the Mac Music (formerly iTunes) app.
- class baclassic.macmusicapp.MacMusicAppMusicPlayer[source]¶
Bases:
MusicPlayerA music-player that utilizes the macOS Music.app for playback.
Allows selecting playlists as entries.
- get_playlists(callback: Callable) None[source]¶
Asynchronously fetch the list of available iTunes playlists.
- on_select_entry(callback: Callable[[Any], None], current_entry: Any, selection_target_name: str) bauiv1.MainWindow[source]¶
Present a GUI to select an entry.
The callback should be called with a valid entry or None to signify that the default soundtrack should be used..
baclassic.osmusic module¶
Music playback using OS functionality exposed through the C++ layer.
- class baclassic.osmusic.OSMusicPlayer[source]¶
Bases:
MusicPlayerMusic player that talks to internal C++ layer for functionality.
(internal)
- classmethod get_valid_music_file_extensions() list[str][source]¶
Return file extensions for types playable on this device.
- on_select_entry(callback: Callable[[Any], None], current_entry: Any, selection_target_name: str) bauiv1.MainWindow[source]¶
Present a GUI to select an entry.
The callback should be called with a valid entry or None to signify that the default soundtrack should be used..