mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +08:00
paid private hosting now uses tokens instead of tickets
This commit is contained in:
parent
674d4a83eb
commit
aceb9a1a66
96
.efrocachemap
generated
96
.efrocachemap
generated
@ -421,7 +421,7 @@
|
||||
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
|
||||
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
|
||||
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
|
||||
"build/assets/ba_data/data/langdata.json": "e6331203538a066bb79a755ab3a2ddd7",
|
||||
"build/assets/ba_data/data/langdata.json": "e9c687b8c06c4b1df34a933a365ed9e7",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "c62b3037ef3364b84d4f8dd6610854f8",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "3d5523d0004293aa2df02f3f6f3b84f8",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "2f67c6b127ae85492ac552af1a91e95a",
|
||||
@ -430,12 +430,12 @@
|
||||
"build/assets/ba_data/data/languages/czech.json": "74219f9b06ff098387b40f85a5b0124e",
|
||||
"build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "b0900d572c9141897d53d6574c471343",
|
||||
"build/assets/ba_data/data/languages/english.json": "d8aabdfb3c00c0a6b35a8a1f53a02394",
|
||||
"build/assets/ba_data/data/languages/english.json": "ef2b554d37c256132ee9dcb4f6478c4e",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "b53910af2d3946d5ff81386e8c1d35a7",
|
||||
"build/assets/ba_data/data/languages/french.json": "b7d11199756f0eb4f1a745ceee652b2a",
|
||||
"build/assets/ba_data/data/languages/german.json": "198b9860c5b9df7b8e3e30b03d8755cb",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "99db538eeed34be968166075346155cf",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "fd68975cb527ddd7b2b97e84a7ba22d7",
|
||||
"build/assets/ba_data/data/languages/greek.json": "ad3c0d38f34d809824892d6f22808dbf",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "e56f0ffb57321660aa415e97c2dacfc2",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "6b08fea24b72cc805ed0dc59e11c4cd6",
|
||||
@ -450,7 +450,7 @@
|
||||
"build/assets/ba_data/data/languages/russian.json": "4cb481af9d4e2611e0033235a045aa33",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "3c08c748c96c71bd9e1d7291fb8817b6",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "fe339007d6e631d601bf826f949828e3",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "485356283e4375a6b8b7cd06614319db",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "5142a96597d17d8344be96a603da64ac",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "b9fcc523639f55e05c7f4e7914f3321a",
|
||||
"build/assets/ba_data/data/languages/thai.json": "1d665629361f302693dead39de8fa945",
|
||||
@ -4062,50 +4062,50 @@
|
||||
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
||||
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "b825e0ae40e1caeaf036244e635bb78d",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "5068c42c3b7defafbf4bb1ba01c67a53",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "411349ebe46b5a4bcda7211adba5fcf8",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "b719d818a8098da1f1a034ef7a7c2150",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "0273ef65559ac5f39147b875adc79c68",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "a3d46a432dd0bb890d657185a4ad5dea",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "9625783e60e3875d66299b0479432391",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "9dc64227710e2d9d3dd04dbe70a0a994",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "f37e40f0b5447a51cafa3c7dcdd8cf91",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "20e35f51e0fb5f97245741ee6167bfbc",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "0a2d8f1ec1fa12ce13eb5c3893753b9e",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "e0939ffb5eaf75c1ee5ca5f8b6ad9a17",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "6e80134a263106a1a982a07857b77436",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "fa100352069f1eada6a23747d52ec625",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "df2dad13b9b6014a5b7c031daade4833",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "29abf332ae82d899f3d9bf6ac7c01171",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "de0fe26430c34f2935e66d7a8200d5ff",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "11462b669e43541ec9b97efce0540751",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "c96b92af111f9415301073de1d11c816",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "c778f347ac0b71f6730254a40aacbb17",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "1e87ade9bea8c12ac6cb5e531205bae5",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "6c92725a224d085b1d426cc03272ebea",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "1e87ade9bea8c12ac6cb5e531205bae5",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "6c92725a224d085b1d426cc03272ebea",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "16783ffe62e14a64331027989da5001b",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "2db28554169b53a560f2f824c1176dfa",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "16783ffe62e14a64331027989da5001b",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "2db28554169b53a560f2f824c1176dfa",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "73dffd26ad8f5caad5be0659cb50df6d",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "2852099ec1365025c290f9d7f9c4a01e",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "73dffd26ad8f5caad5be0659cb50df6d",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "2852099ec1365025c290f9d7f9c4a01e",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "0e39192fedf0bb0926e409a1cb409833",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "ef6ce2f4ed73d411423d6171f5d31100",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "356af38c464e969d04ee4a2889e9f67a",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "ef6ce2f4ed73d411423d6171f5d31100",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "4f53df80210601028bdec3f22b297c18",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "d5fa0bf70723c976f0b4481429022bbc",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "54257c1026e4296f855d2deee42ba9cb",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "492f317391fdf2a69ab65347fbc5cc53",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "8bc3320036ca1911a8f6c85d40a59172",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "9e137f7c83e37f9b7b43bca9319f9752",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "e9c8975e57c0cfde5dc70e2a5547441c",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "d81182adb2c250030d38f8fda682a610",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "123ecb04f354552c15aa04d3d5047074",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "b992b3d97a1b066a1a2b74911ed4a44d",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "2ea1e068455ae6d7c0afd3ac5c1453bf",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "7b087cf909f3a71f97abd431c9dbce60",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "26a69101cb282d96d48d38032fe2ae73",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "2fca0da9ff9eaa5af16fb6801c4e7b81",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "657ee4258b874631acf4e37028e512ec",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "942499d3619e551deb7f5795e62e9022",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "5ea6ae7ac701fd0b51f3db6b0e554268",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "be20cf570211f03f8b54c94e95caf579",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "c73fabf8be863554d5b899c7ea4a960e",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "bf29cf0164a08a4aa139e39f20f50423",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "e2272883f9c7405402cb967f8e3b2b28",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "15f5b471a04313a13bac43c86f37eb72",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "a7672fb4c4b14a1d88c3435cf2af9675",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "2f733fe4dc422b7d0db04a5ea017ab68",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "d34cf623c2cca17fac7fdc0918de1202",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "45dbf5edad5a9a71608ac1d6d1954923",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "3002abd737297bf395eab0bd60c535d8",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "e9bf6aaa7e18bcf482223a29a609932e",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "ffe8631c0ccc03751b4346fcf52d70ca",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "4241e93e1ea18414ee900046d1a62517",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "ffe8631c0ccc03751b4346fcf52d70ca",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "4241e93e1ea18414ee900046d1a62517",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "cd90771128eda8880ac3f9d8d9fc530b",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "093ec692aa3c6039ccc322d74f2d4448",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "cd90771128eda8880ac3f9d8d9fc530b",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "093ec692aa3c6039ccc322d74f2d4448",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "40f3006295c57114c2b5c467f463dd79",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "9049a93c01002bea0e6a580a106939c3",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "40f3006295c57114c2b5c467f463dd79",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "9049a93c01002bea0e6a580a106939c3",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "07ee17e424c0ea754fd4ec9844063460",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "0f34f852bf368c787f41533230767b3a",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "1dcd03f0cfc75a53c3e682a3a46c96a0",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "0f34f852bf368c787f41533230767b3a",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "4a8ae45bb9474a0d8faccd195dded56f",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "8eb224db25a69e2faed1c6897f73c8b6",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "25740d352aec852365430d305655f0fe",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "3e19f73203116e9db0943e0c4485f459",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "517d6fc942828b4c3de3972d6165238e",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "c681050518fde161af81ae356ec80027",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "6689ba552f0a3761b6acc5375343dbe5",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "3a6f2f59a965348b5e9b54562954da89",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "cb299985623bbcc86015cb103a424ae6",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d",
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
### 1.7.36 (build 21936, api 8, 2024-07-24)
|
||||
### 1.7.36 (build 21939, api 8, 2024-07-24)
|
||||
- Wired up Tokens, BombSquad's new purchasable currency. The first thing these
|
||||
can be used for is storage packs on ballistica.net, but this will expand to
|
||||
other places in the game soon. For a full explanation on why these were added,
|
||||
see https://ballistica.net/whataretokens
|
||||
- Paid private hosting now uses tokens instead of tickets.
|
||||
- Wired up initial support for using asset-packages for bundled assets.
|
||||
- bacloud workspace commands are now a bit smarter; you can now do things like
|
||||
`bacloud workspace put .` or even just `bacloud workspace put` and it will
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21936
|
||||
TARGET_BALLISTICA_BUILD = 21939
|
||||
TARGET_BALLISTICA_VERSION = '1.7.36'
|
||||
|
||||
|
||||
|
||||
@ -109,6 +109,15 @@ class CloudSubsystem(babase.AppSubsystem):
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSPrivatePartyMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSPrivatePartyResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: Message,
|
||||
|
||||
@ -13,14 +13,17 @@ from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, cast, override
|
||||
|
||||
from efro.error import CommunicationError
|
||||
from efro.dataclassio import dataclass_from_dict, dataclass_to_dict
|
||||
import bacommon.cloud
|
||||
from bacommon.net import (
|
||||
PrivateHostingState,
|
||||
PrivateHostingConfig,
|
||||
PrivatePartyConnectResult,
|
||||
)
|
||||
from bauiv1lib.gather import GatherTab
|
||||
from bauiv1lib.gettickets import GetTicketsWindow, show_get_tickets_prompt
|
||||
|
||||
from bauiv1lib.gettokens import GetTokensWindow, show_get_tokens_prompt
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
|
||||
@ -55,7 +58,9 @@ class PrivateGatherTab(GatherTab):
|
||||
super().__init__(window)
|
||||
self._container: bui.Widget | None = None
|
||||
self._state: State = State()
|
||||
self._last_datacode_refresh_time: float | None = None
|
||||
self._hostingstate = PrivateHostingState()
|
||||
self._v2state: bacommon.cloud.BSPrivatePartyResponse | None = None
|
||||
self._join_sub_tab_text: bui.Widget | None = None
|
||||
self._host_sub_tab_text: bui.Widget | None = None
|
||||
self._update_timer: bui.AppTimer | None = None
|
||||
@ -63,14 +68,15 @@ class PrivateGatherTab(GatherTab):
|
||||
self._c_width: float = 0.0
|
||||
self._c_height: float = 0.0
|
||||
self._last_hosting_state_query_time: float | None = None
|
||||
self._last_v2_state_query_time: float | None = None
|
||||
self._waiting_for_initial_state = True
|
||||
self._waiting_for_start_stop_response = True
|
||||
self._host_playlist_button: bui.Widget | None = None
|
||||
self._host_copy_button: bui.Widget | None = None
|
||||
self._host_connect_button: bui.Widget | None = None
|
||||
self._host_start_stop_button: bui.Widget | None = None
|
||||
self._get_tickets_button: bui.Widget | None = None
|
||||
self._ticket_count_text: bui.Widget | None = None
|
||||
self._get_tokens_button: bui.Widget | None = None
|
||||
self._token_count_text: bui.Widget | None = None
|
||||
self._showing_not_signed_in_screen = False
|
||||
self._create_time = time.time()
|
||||
self._last_action_send_time: float | None = None
|
||||
@ -159,7 +165,9 @@ class PrivateGatherTab(GatherTab):
|
||||
# Prevent taking any action until we've updated our state.
|
||||
self._waiting_for_initial_state = True
|
||||
|
||||
# This will get a state query sent out immediately.
|
||||
# Force some immediate refreshes.
|
||||
self._last_datacode_refresh_time = None
|
||||
self._last_v2_state_query_time = None
|
||||
self._last_action_send_time = None # Ensure we don't ignore response.
|
||||
self._last_hosting_state_query_time = None
|
||||
self._update()
|
||||
@ -263,19 +271,20 @@ class PrivateGatherTab(GatherTab):
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
try:
|
||||
t_str = str(plus.get_v1_account_ticket_count())
|
||||
except Exception:
|
||||
t_str = '?'
|
||||
if self._get_tickets_button:
|
||||
if self._v2state is not None:
|
||||
t_str = str(self._v2state.tokens)
|
||||
else:
|
||||
t_str = '-'
|
||||
|
||||
if self._get_tokens_button:
|
||||
bui.buttonwidget(
|
||||
edit=self._get_tickets_button,
|
||||
label=bui.charstr(bui.SpecialChar.TICKET) + t_str,
|
||||
edit=self._get_tokens_button,
|
||||
label=bui.charstr(bui.SpecialChar.TOKEN) + t_str,
|
||||
)
|
||||
if self._ticket_count_text:
|
||||
if self._token_count_text:
|
||||
bui.textwidget(
|
||||
edit=self._ticket_count_text,
|
||||
text=bui.charstr(bui.SpecialChar.TICKET) + t_str,
|
||||
edit=self._token_count_text,
|
||||
text=bui.charstr(bui.SpecialChar.TOKEN) + t_str,
|
||||
)
|
||||
|
||||
def _update(self) -> None:
|
||||
@ -292,11 +301,11 @@ class PrivateGatherTab(GatherTab):
|
||||
# If we're not signed in, just refresh to show that.
|
||||
if (
|
||||
plus.get_v1_account_state() != 'signed_in'
|
||||
and self._showing_not_signed_in_screen
|
||||
):
|
||||
or plus.accounts.primary is None
|
||||
) and not self._showing_not_signed_in_screen:
|
||||
self._refresh_sub_tab()
|
||||
else:
|
||||
# Query an updated state periodically.
|
||||
# Query an updated v1 state periodically.
|
||||
if (
|
||||
self._last_hosting_state_query_time is None
|
||||
or now - self._last_hosting_state_query_time > 15.0
|
||||
@ -309,23 +318,78 @@ class PrivateGatherTab(GatherTab):
|
||||
'expire_time': time.time() + 20,
|
||||
},
|
||||
callback=bui.WeakCall(
|
||||
self._hosting_state_idle_response
|
||||
self._idle_hosting_state_response
|
||||
),
|
||||
)
|
||||
plus.run_v1_account_transactions()
|
||||
else:
|
||||
self._hosting_state_idle_response(None)
|
||||
self._idle_hosting_state_response(None)
|
||||
self._last_hosting_state_query_time = now
|
||||
|
||||
def _hosting_state_idle_response(
|
||||
# Query an updated v2 state periodically.
|
||||
if (
|
||||
self._last_v2_state_query_time is None
|
||||
or now - self._last_v2_state_query_time > 12.0
|
||||
):
|
||||
self._debug_server_comm('querying pp v2 state')
|
||||
|
||||
if plus.accounts.primary is not None:
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSPrivatePartyMessage(
|
||||
need_datacode=(
|
||||
self._last_datacode_refresh_time is None
|
||||
or time.monotonic()
|
||||
- self._last_datacode_refresh_time
|
||||
> 30.0
|
||||
)
|
||||
),
|
||||
on_response=bui.WeakCall(
|
||||
self._on_private_party_query_response
|
||||
),
|
||||
)
|
||||
|
||||
self._last_v2_state_query_time = now
|
||||
|
||||
def _on_private_party_query_response(
|
||||
self, response: bacommon.cloud.BSPrivatePartyResponse | Exception
|
||||
) -> None:
|
||||
if isinstance(response, Exception):
|
||||
self._debug_server_comm('got pp v2 state response (err)')
|
||||
# We expect comm errors sometimes. Make noise on anything else.
|
||||
if not isinstance(response, CommunicationError):
|
||||
logging.exception('Error on private-party-query-response')
|
||||
return
|
||||
|
||||
# Ignore if something went wrong server-side.
|
||||
if not response.success:
|
||||
self._debug_server_comm('got pp v2 state response (serverside err)')
|
||||
return
|
||||
|
||||
self._debug_server_comm('got pp v2 state response')
|
||||
|
||||
existing_datacode = (
|
||||
None if self._v2state is None else self._v2state.datacode
|
||||
)
|
||||
|
||||
self._v2state = response
|
||||
if self._v2state.datacode is None:
|
||||
# We don't fetch datacode each time; preserve our existing
|
||||
# if we didn't.
|
||||
self._v2state.datacode = existing_datacode
|
||||
else:
|
||||
# If we *did* fetch it, note the time.
|
||||
self._last_datacode_refresh_time = time.monotonic()
|
||||
|
||||
def _idle_hosting_state_response(
|
||||
self, result: dict[str, Any] | None
|
||||
) -> None:
|
||||
# This simply passes through to our standard response handler.
|
||||
# The one exception is if we've recently sent an action to the
|
||||
# server (start/stop hosting/etc.) In that case we want to ignore
|
||||
# idle background updates and wait for the response to our action.
|
||||
# (this keeps the button showing 'one moment...' until the change
|
||||
# takes effect, etc.)
|
||||
# server (start/stop hosting/etc.) In that case we want to
|
||||
# ignore idle background updates and wait for the response to
|
||||
# our action. (this keeps the button showing 'one moment...'
|
||||
# until the change takes effect, etc.)
|
||||
if (
|
||||
self._last_action_send_time is not None
|
||||
and time.time() - self._last_action_send_time < 5.0
|
||||
@ -354,8 +418,8 @@ class PrivateGatherTab(GatherTab):
|
||||
else:
|
||||
self._debug_server_comm('private party state response errored')
|
||||
|
||||
# Hmm I guess let's just ignore failed responses?...
|
||||
# Or should we show some sort of error state to the user?...
|
||||
# Hmm I guess let's just ignore failed responses?... Or should
|
||||
# we show some sort of error state to the user?...
|
||||
if result is None or state is None:
|
||||
return
|
||||
|
||||
@ -369,14 +433,17 @@ class PrivateGatherTab(GatherTab):
|
||||
if playsound:
|
||||
bui.getsound('click01').play()
|
||||
|
||||
# If switching from join to host, do a fresh state query.
|
||||
# If switching from join to host, force some refreshes.
|
||||
if self._state.sub_tab is SubTabType.JOIN and value is SubTabType.HOST:
|
||||
# Prevent taking any action until we've gotten a fresh state.
|
||||
# Prevent taking any action until we've gotten a fresh
|
||||
# state.
|
||||
self._waiting_for_initial_state = True
|
||||
|
||||
# This will get a state query sent out immediately.
|
||||
# Get some refreshes going immediately.
|
||||
self._last_hosting_state_query_time = None
|
||||
self._last_action_send_time = None # So we don't ignore response.
|
||||
self._last_datacode_refresh_time = None
|
||||
self._last_v2_state_query_time = None
|
||||
self._update()
|
||||
|
||||
self._state.sub_tab = value
|
||||
@ -403,14 +470,14 @@ class PrivateGatherTab(GatherTab):
|
||||
self._host_copy_button,
|
||||
self._host_connect_button,
|
||||
self._host_start_stop_button,
|
||||
self._get_tickets_button,
|
||||
self._get_tokens_button,
|
||||
]
|
||||
|
||||
def _refresh_sub_tab(self) -> None:
|
||||
assert self._container
|
||||
|
||||
# Store an index for our current selection so we can
|
||||
# reselect the equivalent recreated widget if possible.
|
||||
# Store an index for our current selection so we can reselect
|
||||
# the equivalent recreated widget if possible.
|
||||
selindex: int | None = None
|
||||
selchild = self._container.get_selected_child()
|
||||
if selchild is not None:
|
||||
@ -481,13 +548,13 @@ class PrivateGatherTab(GatherTab):
|
||||
edit=self._join_party_code_text, on_return_press_call=btn.activate
|
||||
)
|
||||
|
||||
def _on_get_tickets_press(self) -> None:
|
||||
def _on_get_tokens_press(self) -> None:
|
||||
if self._waiting_for_start_stop_response:
|
||||
return
|
||||
|
||||
# Bring up get-tickets window and then kill ourself (we're on the
|
||||
# overlay layer so we'd show up above it).
|
||||
GetTicketsWindow(modal=True, origin_widget=self._get_tickets_button)
|
||||
# Bring up get-tickets window and then kill ourself (we're on
|
||||
# the overlay layer so we'd show up above it).
|
||||
GetTokensWindow(origin_widget=self._get_tokens_button)
|
||||
|
||||
def _build_host_tab(self) -> None:
|
||||
# pylint: disable=too-many-branches
|
||||
@ -498,13 +565,20 @@ class PrivateGatherTab(GatherTab):
|
||||
assert plus is not None
|
||||
|
||||
hostingstate = self._hostingstate
|
||||
|
||||
havegoldpass = self._v2state is not None and self._v2state.gold_pass
|
||||
|
||||
# We use both v1 and v2 account functionality here (sigh). So
|
||||
# make sure we're signed in on both ends.
|
||||
|
||||
# Make sure the V1 side is good to go.
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
bui.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=200,
|
||||
maxwidth=self._c_width * 0.8,
|
||||
scale=0.8,
|
||||
color=(0.6, 0.56, 0.6),
|
||||
position=(self._c_width * 0.5, self._c_height * 0.5),
|
||||
@ -512,14 +586,31 @@ class PrivateGatherTab(GatherTab):
|
||||
)
|
||||
self._showing_not_signed_in_screen = True
|
||||
return
|
||||
|
||||
# Make sure the V2 side is good to go.
|
||||
if plus.accounts.primary is None:
|
||||
bui.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._c_width * 0.8,
|
||||
scale=0.8,
|
||||
color=(0.6, 0.56, 0.6),
|
||||
position=(self._c_width * 0.5, self._c_height * 0.5),
|
||||
text=bui.Lstr(resource='v2AccountRequiredText'),
|
||||
)
|
||||
self._showing_not_signed_in_screen = True
|
||||
return
|
||||
|
||||
self._showing_not_signed_in_screen = False
|
||||
|
||||
# At first we don't want to show anything until we've gotten a state.
|
||||
# Update: In this situation we now simply show our existing state
|
||||
# but give the start/stop button a loading message and disallow its
|
||||
# use. This keeps things a lot less jumpy looking and allows selecting
|
||||
# playlists/etc without having to wait for the server each time
|
||||
# back to the ui.
|
||||
# At first we don't want to show anything until we've gotten a
|
||||
# state. Update: In this situation we now simply show our
|
||||
# existing state but give the start/stop button a loading
|
||||
# message and disallow its use. This keeps things a lot less
|
||||
# jumpy looking and allows selecting playlists/etc without
|
||||
# having to wait for the server each time back to the ui.
|
||||
if self._waiting_for_initial_state and bool(False):
|
||||
bui.textwidget(
|
||||
parent=self._container,
|
||||
@ -537,16 +628,21 @@ class PrivateGatherTab(GatherTab):
|
||||
)
|
||||
return
|
||||
|
||||
# If we're not currently hosting and hosting requires tickets,
|
||||
# If we're not currently hosting and hosting requires tokens,
|
||||
# Show our count (possibly with a link to purchase more).
|
||||
if (
|
||||
not self._waiting_for_initial_state
|
||||
and hostingstate.party_code is None
|
||||
and hostingstate.tickets_to_host_now != 0
|
||||
and not havegoldpass
|
||||
):
|
||||
if not bui.app.ui_v1.use_toolbars:
|
||||
if bui.app.classic.allow_ticket_purchases:
|
||||
self._get_tickets_button = bui.buttonwidget(
|
||||
|
||||
# Currently have no allow_token_purchases value like
|
||||
# we had with tickets; just assuming we always allow.
|
||||
if bool(True):
|
||||
# if bui.app.classic.allow_ticket_purchases:
|
||||
self._get_tokens_button = bui.buttonwidget(
|
||||
parent=self._container,
|
||||
position=(
|
||||
self._c_width - 210 + 125,
|
||||
@ -555,24 +651,25 @@ class PrivateGatherTab(GatherTab):
|
||||
autoselect=True,
|
||||
scale=0.6,
|
||||
size=(120, 60),
|
||||
textcolor=(0.2, 1, 0.2),
|
||||
label=bui.charstr(bui.SpecialChar.TICKET),
|
||||
textcolor=(1.0, 0.6, 0.0),
|
||||
label=bui.charstr(bui.SpecialChar.TOKEN),
|
||||
color=(0.65, 0.5, 0.8),
|
||||
on_activate_call=self._on_get_tickets_press,
|
||||
on_activate_call=self._on_get_tokens_press,
|
||||
)
|
||||
else:
|
||||
self._ticket_count_text = bui.textwidget(
|
||||
self._token_count_text = bui.textwidget(
|
||||
parent=self._container,
|
||||
scale=0.6,
|
||||
position=(
|
||||
self._c_width - 210 + 125,
|
||||
self._c_height - 44,
|
||||
),
|
||||
color=(0.2, 1, 0.2),
|
||||
color=(1.0, 0.6, 0.0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
# Set initial ticket count.
|
||||
|
||||
# Set initial token count.
|
||||
self._update_currency_ui()
|
||||
|
||||
v = self._c_height - 90
|
||||
@ -594,7 +691,8 @@ class PrivateGatherTab(GatherTab):
|
||||
|
||||
v -= 100
|
||||
if hostingstate.party_code is None:
|
||||
# We've got no current party running; show options to set one up.
|
||||
# We've got no current party running; show options to set
|
||||
# one up.
|
||||
bui.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
@ -713,8 +811,14 @@ class PrivateGatherTab(GatherTab):
|
||||
)
|
||||
),
|
||||
)
|
||||
elif havegoldpass:
|
||||
# If we have a gold pass, none of the
|
||||
# timing/free-server-availability info below is relevant to
|
||||
# us.
|
||||
pass
|
||||
elif hostingstate.free_host_minutes_remaining is not None:
|
||||
# If we've been pre-approved to start/stop for free, show that.
|
||||
# If we've been pre-approved to start/stop for free, show
|
||||
# that.
|
||||
bui.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
@ -811,12 +915,12 @@ class PrivateGatherTab(GatherTab):
|
||||
resource='gatherWindow.hostingUnavailableText'
|
||||
)
|
||||
elif hostingstate.party_code is None:
|
||||
ticon = bui.charstr(bui.SpecialChar.TICKET)
|
||||
nowtickets = hostingstate.tickets_to_host_now
|
||||
if nowtickets > 0:
|
||||
ticon = bui.charstr(bui.SpecialChar.TOKEN)
|
||||
nowtokens = hostingstate.tokens_to_host_now
|
||||
if nowtokens > 0 and not havegoldpass:
|
||||
btnlabel = bui.Lstr(
|
||||
resource='gatherWindow.startHostingPaidText',
|
||||
subs=[('${COST}', f'{ticon}{nowtickets}')],
|
||||
subs=[('${COST}', f'{ticon}{nowtokens}')],
|
||||
)
|
||||
else:
|
||||
btnlabel = bui.Lstr(
|
||||
@ -867,8 +971,8 @@ class PrivateGatherTab(GatherTab):
|
||||
)
|
||||
|
||||
def _connect_to_party_code(self, code: str) -> None:
|
||||
# Ignore attempted followup sends for a few seconds.
|
||||
# (this will reset if we get a response)
|
||||
# Ignore attempted followup sends for a few seconds. (this will
|
||||
# reset if we get a response)
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
@ -915,21 +1019,30 @@ class PrivateGatherTab(GatherTab):
|
||||
|
||||
bui.getsound('click01').play()
|
||||
|
||||
# We need our v2 info for this.
|
||||
if self._v2state is None or self._v2state.datacode is None:
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='internal.unavailableNoConnectionText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
# If we're not hosting, start.
|
||||
if self._hostingstate.party_code is None:
|
||||
# If there's a ticket cost, make sure we have enough tickets.
|
||||
if self._hostingstate.tickets_to_host_now > 0:
|
||||
ticket_count: int | None
|
||||
try:
|
||||
ticket_count = plus.get_v1_account_ticket_count()
|
||||
except Exception:
|
||||
# FIXME: should add a bui.NotSignedInError we can use here.
|
||||
ticket_count = None
|
||||
ticket_cost = self._hostingstate.tickets_to_host_now
|
||||
if ticket_count is not None and ticket_count < ticket_cost:
|
||||
show_get_tickets_prompt()
|
||||
# If there's a token cost, make sure we have enough tokens
|
||||
# or a gold pass.
|
||||
if self._hostingstate.tokens_to_host_now > 0:
|
||||
|
||||
if (
|
||||
not self._v2state.gold_pass
|
||||
and self._v2state.tokens
|
||||
< self._hostingstate.tokens_to_host_now
|
||||
):
|
||||
show_get_tokens_prompt()
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
self._last_action_send_time = time.time()
|
||||
plus.add_v1_account_transaction(
|
||||
{
|
||||
@ -937,6 +1050,7 @@ class PrivateGatherTab(GatherTab):
|
||||
'config': dataclass_to_dict(self._hostingconfig),
|
||||
'region_pings': bui.app.net.zone_pings,
|
||||
'expire_time': time.time() + 20,
|
||||
'datacode': self._v2state.datacode,
|
||||
},
|
||||
callback=bui.WeakCall(self._hosting_state_response),
|
||||
)
|
||||
|
||||
@ -779,3 +779,31 @@ class GetTokensWindow(bui.Window):
|
||||
|
||||
def _on_learn_more_press(self, url: str) -> None:
|
||||
bui.open_url(url)
|
||||
|
||||
|
||||
def show_get_tokens_prompt() -> None:
|
||||
"""Show a 'not enough tokens' prompt with an option to purchase more.
|
||||
|
||||
Note that the purchase option may not always be available
|
||||
depending on the build of the game.
|
||||
"""
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
|
||||
# Currently always allowing token purchases.
|
||||
if bool(True):
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource='tokens.notEnoughTokensText'),
|
||||
GetTokensWindow,
|
||||
ok_text=bui.Lstr(resource='tokens.getTokensText'),
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
else:
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource='tokens.notEnoughTokensText'),
|
||||
cancel_button=False,
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
|
||||
@ -80,6 +80,11 @@ TextGraphics::TextGraphics() {
|
||||
g.y_size *= 0.55f;
|
||||
}
|
||||
}
|
||||
// Special handling of tokens icon.
|
||||
if (index == 29) {
|
||||
extra_advance += 0.12f;
|
||||
}
|
||||
|
||||
// Special case for v2 logo.
|
||||
if (index == 99) {
|
||||
g.pen_offset_y += 0.25f;
|
||||
|
||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
||||
namespace ballistica {
|
||||
|
||||
// These are set automatically via script; don't modify them here.
|
||||
const int kEngineBuildNumber = 21936;
|
||||
const int kEngineBuildNumber = 21939;
|
||||
const char* kEngineVersion = "1.7.36";
|
||||
const int kEngineApiVersion = 8;
|
||||
|
||||
|
||||
@ -288,3 +288,27 @@ class StoreQueryResponse(Response):
|
||||
|
||||
available_purchases: Annotated[list[Purchase], IOAttrs('p')]
|
||||
token_info_url: Annotated[str, IOAttrs('tiu')]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSPrivatePartyMessage(Message):
|
||||
"""Message asking about info we need for private-party UI."""
|
||||
|
||||
need_datacode: Annotated[bool, IOAttrs('d')]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [BSPrivatePartyResponse]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSPrivatePartyResponse(Response):
|
||||
"""Here's that private party UI info you asked for, boss."""
|
||||
|
||||
success: Annotated[bool, IOAttrs('s')]
|
||||
tokens: Annotated[int, IOAttrs('t')]
|
||||
gold_pass: Annotated[bool, IOAttrs('g')]
|
||||
datacode: Annotated[str | None, IOAttrs('d')]
|
||||
|
||||
@ -64,6 +64,7 @@ class PrivateHostingState:
|
||||
unavailable_error: str | None = None
|
||||
party_code: str | None = None
|
||||
tickets_to_host_now: int = 0
|
||||
tokens_to_host_now: int = 0
|
||||
minutes_until_free_host: float | None = None
|
||||
free_host_minutes_remaining: float | None = None
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user