syncing changes from ballistica/master

This commit is contained in:
Ayush Saini 2025-02-09 00:17:58 +05:30
parent 2a07c0c840
commit 8913080562
227 changed files with 15756 additions and 12772 deletions

View file

@ -1,7 +1,6 @@
# Released under the MIT License. See LICENSE for details.
#
"""Session and Activity for displaying the main menu bg."""
# pylint: disable=too-many-lines
from __future__ import annotations
@ -16,6 +15,8 @@ import bauiv1 as bui
if TYPE_CHECKING:
from typing import Any
import bacommon.bs
class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
"""Activity showing the rotating main menu bg stuff."""
@ -43,55 +44,23 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
self._update_timer: bs.Timer | None = None
self._news: NewsDisplay | None = None
self._attract_mode_timer: bs.Timer | None = None
self._logo_rotate_timer: bs.Timer | None = None
@override
def on_transition_in(self) -> None:
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
super().on_transition_in()
random.seed(123)
app = bs.app
env = app.env
assert app.classic is not None
plus = bui.app.plus
plus = bs.app.plus
assert plus is not None
# FIXME: We shouldn't be doing things conditionally based on whether
# the host is VR mode or not (clients may differ in that regard).
# Any differences need to happen at the engine level so everyone
# sees things in their own optimal way.
vr_mode = bs.app.env.vr
if not bs.app.ui_v1.use_toolbars:
color = (1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6)
# FIXME: Need a node attr for vr-specific-scale.
scale = (
0.9
if (app.ui_v1.uiscale is bs.UIScale.SMALL or vr_mode)
else 0.7
)
self.my_name = bs.NodeActor(
bs.newnode(
'text',
attrs={
'v_attach': 'bottom',
'h_align': 'center',
'color': color,
'flatness': 1.0,
'shadow': 1.0 if vr_mode else 0.5,
'scale': scale,
'position': (0, 10),
'vr_depth': -10,
'text': '\xa9 2011-2024 Eric Froemling',
},
)
)
# Throw up some text that only clients can see so they know that the
# host is navigating menus while they're just staring at an
# Throw up some text that only clients can see so they know that
# the host is navigating menus while they're just staring at an
# empty-ish screen.
tval = bs.Lstr(
resource='hostIsNavigatingMenusText',
@ -109,73 +78,16 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
},
)
)
if not app.classic.main_menu_did_initial_transition and hasattr(
self, 'my_name'
if (
not app.classic.main_menu_did_initial_transition
and self.my_name is not None
):
assert self.my_name is not None
assert self.my_name.node
bs.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0})
# FIXME: We shouldn't be doing things conditionally based on whether
# the host is vr mode or not (clients may not be or vice versa).
# Any differences need to happen at the engine level so everyone sees
# things in their own optimal way.
vr_mode = app.env.vr
uiscale = app.ui_v1.uiscale
# In cases where we're doing lots of dev work lets always show the
# build number.
force_show_build_number = False
if not bs.app.ui_v1.use_toolbars:
if env.debug or env.test or force_show_build_number:
if env.debug:
text = bs.Lstr(
value='${V} (${B}) (${D})',
subs=[
('${V}', app.env.engine_version),
('${B}', str(app.env.engine_build_number)),
('${D}', bs.Lstr(resource='debugText')),
],
)
else:
text = bs.Lstr(
value='${V} (${B})',
subs=[
('${V}', app.env.engine_version),
('${B}', str(app.env.engine_build_number)),
],
)
else:
text = bs.Lstr(
value='${V}', subs=[('${V}', app.env.engine_version)]
)
scale = 0.9 if (uiscale is bs.UIScale.SMALL or vr_mode) else 0.7
color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7)
self.version = bs.NodeActor(
bs.newnode(
'text',
attrs={
'v_attach': 'bottom',
'h_attach': 'right',
'h_align': 'right',
'flatness': 1.0,
'vr_depth': -10,
'shadow': 1.0 if vr_mode else 0.5,
'color': color,
'scale': scale,
'position': (-260, 10) if vr_mode else (-10, 10),
'text': text,
},
)
)
if not app.classic.main_menu_did_initial_transition:
assert self.version.node
bs.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0})
# Throw in test build info.
self.beta_info = self.beta_info_2 = None
if env.test and not (env.demo or env.arcade):
if env.test:
pos = (230, 35)
self.beta_info = bs.NodeActor(
bs.newnode(
@ -292,125 +204,20 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
self._update()
# Hopefully this won't hitch but lets space these out anyway.
bui.add_clean_frame_callback(bs.WeakCall(self._start_preloads))
bs.add_clean_frame_callback(bs.WeakCall(self._start_preloads))
random.seed()
if not (env.demo or env.arcade) and not app.ui_v1.use_toolbars:
self._news = NewsDisplay(self)
# Need to update this for toolbar mode; currenly doesn't fit.
if bool(False):
if not (env.demo or env.arcade):
self._news = NewsDisplay(self)
self._attract_mode_timer = bs.Timer(
3.12, self._update_attract_mode, repeat=True
)
# Bring up the last place we were, or start at the main menu otherwise.
with bs.ContextRef.empty():
from bauiv1lib import specialoffer
assert bs.app.classic is not None
if bui.app.env.headless:
# UI stuff fails now in headless builds; avoid it.
pass
elif bool(False):
uicontroller = bs.app.ui_v1.controller
assert uicontroller is not None
uicontroller.show_main_menu()
else:
main_menu_location = bs.app.ui_v1.get_main_menu_location()
# When coming back from a kiosk-mode game, jump to
# the kiosk start screen.
if env.demo or env.arcade:
# pylint: disable=cyclic-import
from bauiv1lib.kiosk import KioskWindow
bs.app.ui_v1.set_main_menu_window(
KioskWindow().get_root_widget(),
from_window=False, # Disable check here.
)
# ..or in normal cases go back to the main menu
else:
if main_menu_location == 'Gather':
# pylint: disable=cyclic-import
from bauiv1lib.gather import GatherWindow
bs.app.ui_v1.set_main_menu_window(
GatherWindow(transition=None).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Watch':
# pylint: disable=cyclic-import
from bauiv1lib.watch import WatchWindow
bs.app.ui_v1.set_main_menu_window(
WatchWindow(transition=None).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Team Game Select':
# pylint: disable=cyclic-import
from bauiv1lib.playlist.browser import (
PlaylistBrowserWindow,
)
bs.app.ui_v1.set_main_menu_window(
PlaylistBrowserWindow(
sessiontype=bs.DualTeamSession, transition=None
).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Free-for-All Game Select':
# pylint: disable=cyclic-import
from bauiv1lib.playlist.browser import (
PlaylistBrowserWindow,
)
bs.app.ui_v1.set_main_menu_window(
PlaylistBrowserWindow(
sessiontype=bs.FreeForAllSession,
transition=None,
).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Coop Select':
# pylint: disable=cyclic-import
from bauiv1lib.coop.browser import CoopBrowserWindow
bs.app.ui_v1.set_main_menu_window(
CoopBrowserWindow(
transition=None
).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Benchmarks & Stress Tests':
# pylint: disable=cyclic-import
from bauiv1lib.debug import DebugWindow
bs.app.ui_v1.set_main_menu_window(
DebugWindow(transition=None).get_root_widget(),
from_window=False, # Disable check here.
)
else:
# pylint: disable=cyclic-import
from bauiv1lib.mainmenu import MainMenuWindow
bs.app.ui_v1.set_main_menu_window(
MainMenuWindow(transition=None).get_root_widget(),
from_window=False, # Disable check here.
)
# attempt to show any pending offers immediately.
# If that doesn't work, try again in a few seconds
# (we may not have heard back from the server)
# ..if that doesn't work they'll just have to wait
# until the next opportunity.
if not specialoffer.show_offer():
def try_again() -> None:
if not specialoffer.show_offer():
# Try one last time..
bui.apptimer(2.0, specialoffer.show_offer)
bui.apptimer(2.0, try_again)
app.classic.invoke_main_menu_ui()
app.classic.main_menu_did_initial_transition = True
@ -445,7 +252,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
y = 20
base_scale = 1.1
self._word_actors = []
base_delay = 1.0
base_delay = 0.8
delay = base_delay
delay_inc = 0.02
@ -628,6 +435,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
word: str,
x: float,
y: float,
*,
scale: float = 1.0,
delay: float = 0.0,
vr_depth_offset: float = 0.0,
@ -676,9 +484,8 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
)
self._word_actors.append(word_obj)
# Add a bit of stop-motion-y jitter to the logo
# (unless we're in VR mode in which case its best to
# leave things still).
# Add a bit of stop-motion-y jitter to the logo (unless we're in
# VR mode in which case its best to leave things still).
if not bs.app.env.vr:
cmb: bs.Node | None
cmb2: bs.Node | None
@ -757,13 +564,13 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
y: float,
scale: float,
delay: float,
*,
custom_texture: str | None = None,
jitter_scale: float = 1.0,
rotate: float = 0.0,
vr_depth_offset: float = 0.0,
) -> None:
# pylint: disable=too-many-locals
# Temp easter goodness.
if custom_texture is None:
custom_texture = self._get_custom_logo_tex_name()
self._custom_logo_tex_name = custom_texture
@ -776,60 +583,92 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
if custom_texture is not None
else bs.getmesh('logoTransparent')
)
logo = bs.NodeActor(
bs.newnode(
'image',
attrs={
'texture': ltex,
'mesh_opaque': mopaque,
'mesh_transparent': mtrans,
'vr_depth': -10 + vr_depth_offset,
'rotate': rotate,
'attach': 'center',
'tilt_translate': 0.21,
'absolute_scale': True,
},
)
)
logo_attrs = {
'position': (x, y),
'texture': ltex,
'mesh_opaque': mopaque,
'mesh_transparent': mtrans,
'vr_depth': -10 + vr_depth_offset,
'rotate': rotate,
'attach': 'center',
'tilt_translate': 0.21,
'absolute_scale': True,
}
if custom_texture is None:
logo_attrs['scale'] = (2000.0, 2000.0)
logo = bs.NodeActor(bs.newnode('image', attrs=logo_attrs))
self._logo_node = logo.node
self._word_actors.append(logo)
# Add a bit of stop-motion-y jitter to the logo
# (unless we're in VR mode in which case its best to
# leave things still).
# Add a bit of stop-motion-y jitter to the logo (unless we're in
# VR mode in which case its best to leave things still).
assert logo.node
if not bs.app.env.vr:
def jitter() -> None:
if not bs.app.env.vr:
cmb = bs.newnode('combine', owner=logo.node, attrs={'size': 2})
cmb.connectattr('output', logo.node, 'position')
keys = {}
time_v = 0.0
# Gen some random keys for that stop-motion-y look
for _i in range(10):
keys[time_v] = (
x + (random.random() - 0.5) * 0.7 * jitter_scale
)
time_v += random.random() * 0.1
bs.animate(cmb, 'input0', keys, loop=True)
keys = {}
time_v = 0.0
for _i in range(10):
keys[time_v * self._ts] = (
y + (random.random() - 0.5) * 0.7 * jitter_scale
)
time_v += random.random() * 0.1
bs.animate(cmb, 'input1', keys, loop=True)
# Do a fun spinny animation on the logo the first time in.
if (
custom_texture is None
and bs.app.classic is not None
and not bs.app.classic.main_menu_did_initial_transition
):
jitter()
cmb = bs.newnode('combine', owner=logo.node, attrs={'size': 2})
cmb.connectattr('output', logo.node, 'position')
keys = {}
time_v = 0.0
# Gen some random keys for that stop-motion-y look
for _i in range(10):
keys[time_v] = x + (random.random() - 0.5) * 0.7 * jitter_scale
time_v += random.random() * 0.1
bs.animate(cmb, 'input0', keys, loop=True)
keys = {}
time_v = 0.0
for _i in range(10):
keys[time_v * self._ts] = (
y + (random.random() - 0.5) * 0.7 * jitter_scale
)
time_v += random.random() * 0.1
bs.animate(cmb, 'input1', keys, loop=True)
delay = 0.0
keys = {
delay: 5000.0 * scale,
delay + 0.4: 530.0 * scale,
delay + 0.45: 620.0 * scale,
delay + 0.5: 590.0 * scale,
delay + 0.55: 605.0 * scale,
delay + 0.6: 600.0 * scale,
}
bs.animate(cmb, 'input0', keys)
bs.animate(cmb, 'input1', keys)
cmb.connectattr('output', logo.node, 'scale')
keys = {
delay: 100.0,
delay + 0.4: 370.0,
delay + 0.45: 357.0,
delay + 0.5: 360.0,
}
bs.animate(logo.node, 'rotate', keys)
else:
logo.node.position = (x, y)
# For all other cases do a simple scale up animation.
jitter()
cmb = bs.newnode('combine', owner=logo.node, attrs={'size': 2})
cmb = bs.newnode('combine', owner=logo.node, attrs={'size': 2})
keys = {
delay: 0.0,
delay + 0.1: 700.0 * scale,
delay + 0.2: 600.0 * scale,
}
bs.animate(cmb, 'input0', keys)
bs.animate(cmb, 'input1', keys)
cmb.connectattr('output', logo.node, 'scale')
keys = {
delay: 0.0,
delay + 0.1: 700.0 * scale,
delay + 0.2: 600.0 * scale,
}
bs.animate(cmb, 'input0', keys)
bs.animate(cmb, 'input1', keys)
cmb.connectattr('output', logo.node, 'scale')
def _start_preloads(self) -> None:
# FIXME: The func that calls us back doesn't save/restore state
@ -879,8 +718,8 @@ class NewsDisplay:
self._used_phrases: list[str] = []
self._phrase_change_timer: bs.Timer | None = None
# If we're signed in, fetch news immediately.
# Otherwise wait until we are signed in.
# If we're signed in, fetch news immediately. Otherwise wait
# until we are signed in.
self._fetch_timer: bs.Timer | None = bs.Timer(
1.0, bs.WeakCall(self._try_fetching_news), repeat=True
)
@ -913,8 +752,8 @@ class NewsDisplay:
app = bs.app
assert app.classic is not None
# If our news is way out of date, lets re-request it;
# otherwise, rotate our phrase.
# If our news is way out of date, lets re-request it; otherwise,
# rotate our phrase.
assert app.classic.main_menu_last_news_fetch_time is not None
if time.time() - app.classic.main_menu_last_news_fetch_time > 600.0:
self._fetch_news()
@ -981,17 +820,16 @@ class NewsDisplay:
self._text.node.text = val
def _got_news(self, news: str) -> None:
# Run this stuff in the context of our activity since we
# need to make nodes and stuff.. should fix the serverget
# call so it.
# Run this stuff in the context of our activity since we need to
# make nodes and stuff.. should fix the serverget call so it.
activity = self._activity()
if activity is None or activity.expired:
return
with activity.context:
self._phrases.clear()
# Show upcoming achievements in non-vr versions
# (currently too hard to read in vr).
# Show upcoming achievements in non-vr versions (currently
# too hard to read in vr).
self._used_phrases = (['__ACH__'] if not bs.app.env.vr else []) + [
s for s in news.split('<br>\n') if s != ''
]