From ee007b15dbb6f985ace5eeaf22f6ccd5f0fb2b24 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 22 Jul 2024 21:50:39 -0700 Subject: [PATCH] more work on tokens --- .efrocachemap | 88 +++---- CHANGELOG.md | 6 +- src/assets/ba_data/python/baenv.py | 2 +- .../ba_data/python/bauiv1lib/gettokens.py | 245 +++++++++++++++--- .../platform/apple/base_platform_apple.cc | 4 +- .../base/platform/apple/base_platform_apple.h | 4 +- src/ballistica/base/platform/base_platform.cc | 2 +- src/ballistica/base/platform/base_platform.h | 4 +- src/ballistica/shared/ballistica.cc | 2 +- tools/bacommon/cloud.py | 2 + tools/efrotools/sync.py | 5 +- 11 files changed, 266 insertions(+), 98 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index a62b1c94..5789cc14 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -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": "de1a31ddd37764c6a31c6c619a0069fe", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "1a4894c9eb324e6d2a442f72e5651c2c", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "1999d90958ff312203a290aaff97a24f", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "9a33cde90e447754e0b669f1e08948b2", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "c52c4b14e87cada2d2de8060caf64ec3", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "4894e58ac2fa3cbff0c0542e33afd94e", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "eee4b5407e69075d925fad94de12c0b8", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "5d041c76ab815765179308a01b6a0028", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "8ae3a85f68553255fa47a86e35cd41b0", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "cd9dac595579b8e19f15eade2cf8155f", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "1ab4f141dd2541ae40e886b5d448d86f", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "fb869f599357cb079851542411b2a852", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "d06777b1f953c4f102d3ddb5b9d79337", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "ac0582306bab0108da45dc53e0c544a7", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "f847c697c1d541bbd1207355065fa988", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "6edc275e5c427a04df8b02b115d2d832", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "473ef626512034b43a8fa54ad66af1ce", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "45f6a37d5e21b45542260f86b7c4784b", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "4d9922c7ba8e15e2059fcef7f87d195a", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "fd57a5b64d0fc65bd04bbfdd4b63965d", - "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "fbfd42ab5d27e3ff921fa9cda02b2b45", - "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "abb5870a4b01cda2c9a958149f759325", - "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "fbfd42ab5d27e3ff921fa9cda02b2b45", - "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "abb5870a4b01cda2c9a958149f759325", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "1b51a49163d412cdd0b1441e3459e6c4", - "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "4a39d8397fb76df3bafa366d8085d1cd", - "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "1b51a49163d412cdd0b1441e3459e6c4", - "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "4a39d8397fb76df3bafa366d8085d1cd", - "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "c4ed230b63e7109de342e045733963e5", - "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "adb7ef762cb92b4c3bbe74a36e8ac6df", - "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "c4ed230b63e7109de342e045733963e5", - "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "adb7ef762cb92b4c3bbe74a36e8ac6df", - "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "0863bb24d2a42598dd20e7b55beb1c02", - "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "1805fd5900917411f0e8032bf3c4734c", - "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "3277c2f61c315e2ca7ed6776ba2363e2", - "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "1805fd5900917411f0e8032bf3c4734c", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "b639992e280ee3a73b764a3e3e58baec", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "5ebaf4315d286080e5789939edfe43ce", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "be8f76ded92473fbab8b28018097456c", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "dcab88e3c14c6f4c4a03dd8617328eaf", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "bab18c50134744a7206ea1ded2d90ab2", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "c6788ba7cd99fc29a0b6ca8351f412b4", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "e61726c963e53ee7746ffbd7ed35c919", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "841fbbd6b87ac5d50ccdda647d8ff909", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "9698e65459797b5a87072643f548f4ab", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "e02eb31d2e4065e0436fc96232248fc5", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "c79f227c4164afcd09ea70f8828c2f22", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "6d4f68f726a373fdc179230a72a92324", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "c285dfc219ba755f5abfbbe09b9aa9b8", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "dd0b580b172574f14ef51789acfcc8f2", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "69619ebd570b57f59ab3648aa6d3590a", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "916f649191e81cc23e35818016e220df", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "c2c725f438afe35aaade8b007d812e46", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "6da83421d80c824fe9fe6f13b5f7991e", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "f621b7c2e34f55dc8af7ca41bc4dc4ed", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "2aa7d4c4008d6be2fc172a2375d47fed", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "c51e187921cff4b389a345a0f87f364b", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "5a74d47d994cbdf24da77462ef66ab55", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "f25707a21481e3c45e7dbefc46b544f0", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "9ace2a7c76cc66b8f9eab4d689a6ea49", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "6e40b5fb42a16bfeeebf71aabeab1007", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "8505048dfc05e7c02328bfbc359e23b3", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "a73f6abea43df032adb422ad5be2f486", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "cba67113f21cca2a51772ca92fc3f113", + "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "61badc0ac176ef98abeba3ffa7a0c6d6", + "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "79862c15f8121428281bb328b3d19e08", + "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "61badc0ac176ef98abeba3ffa7a0c6d6", + "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "79862c15f8121428281bb328b3d19e08", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "b47a86a58800dadefce197ee923c07c7", + "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "7d5c7f92343fa4c0690995a0335afed8", + "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "b47a86a58800dadefce197ee923c07c7", + "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "7d5c7f92343fa4c0690995a0335afed8", + "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "bb72cb9f98d48a5f572733db4095c449", + "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "cc8aea2f632599441196a35fd1dc927a", + "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "bb72cb9f98d48a5f572733db4095c449", + "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "cc8aea2f632599441196a35fd1dc927a", + "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "60b7e716cd73097cd29654a1787dcc5d", + "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "c1c40ab7f37c200b366dc6d4dbceb2a6", + "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "f4cf12b15ecca349357f6fa68541b8e5", + "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "c1c40ab7f37c200b366dc6d4dbceb2a6", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "3d9473e959782490836d1e76f20dc5ad", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "2887132d17a9909f02e6a12110e747a1", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "7fc343bf0a59b0b77496c5a32e53ae4a", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "2d32ced3489090b4331f690ed6e43c22", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "0380d3daa1497385764b2bb190430567", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "a4c2a736cc9f100a1115defa962448a7", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "bfb0fcd3fc53dcfed5022c9880df6033", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a648e37862105c638c05c2e833470764", "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", diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c71e354..e027ca08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -### 1.7.36 (build 21919, api 8, 2024-07-21) +### 1.7.36 (build 21928, api 8, 2024-07-22) +- 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 - 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 diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 09825511..fd70d381 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21919 +TARGET_BALLISTICA_BUILD = 21928 TARGET_BALLISTICA_VERSION = '1.7.36' diff --git a/src/assets/ba_data/python/bauiv1lib/gettokens.py b/src/assets/ba_data/python/bauiv1lib/gettokens.py index e0d04854..e5348c39 100644 --- a/src/assets/ba_data/python/bauiv1lib/gettokens.py +++ b/src/assets/ba_data/python/bauiv1lib/gettokens.py @@ -4,16 +4,15 @@ from __future__ import annotations -import logging +import time from enum import Enum from functools import partial from dataclasses import dataclass from typing import TYPE_CHECKING, assert_never import bacommon.cloud - import bauiv1 as bui -from bauiv1lib.connectivity import wait_for_connectivity + if TYPE_CHECKING: from typing import Any, Callable @@ -58,8 +57,13 @@ class _TxtDef: class GetTokensWindow(bui.Window): """Window for purchasing/acquiring classic tickets.""" - def __del__(self) -> None: - print('~GetTokensWindow()') + class State(Enum): + """What are we doing?""" + + LOADING = 'loading' + NOT_SIGNED_IN = 'not_signed_in' + HAVE_GOLD_PASS = 'have_gold_pass' + SHOWING_STORE = 'showing_store' def __init__( self, @@ -291,6 +295,12 @@ class GetTokensWindow(bui.Window): self._restore_previous_call = restore_previous_call self._textcolor = (0.92, 0.92, 2.0) + self._query_in_flight = False + self._last_query_time = -1.0 + self._last_query_response: bacommon.cloud.StoreQueryResponse | None = ( + None + ) + # If they provided an origin-widget, scale up from that. scale_origin: tuple[float, float] | None if origin_widget is not None: @@ -350,7 +360,7 @@ class GetTokensWindow(bui.Window): bui.containerwidget(edit=self._root_widget, cancel_button=btn) - bui.textwidget( + self._title_text = bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 47), size=(0, 0), @@ -366,6 +376,7 @@ class GetTokensWindow(bui.Window): self._status_text = bui.textwidget( parent=self._root_widget, + size=(0, 0), position=(self._width * 0.5, self._height * 0.5), h_align='center', v_align='center', @@ -374,40 +385,117 @@ class GetTokensWindow(bui.Window): text='Loading...', ) + self._core_widgets = [ + self._back_button, + self._title_text, + self._status_text, + ] + + self._token_count_widget: bui.Widget | None = None + self._smooth_update_timer: bui.AppTimer | None = None + self._smooth_token_count: float | None = None + self._token_count: int = 0 + self._smooth_increase_speed = 1.0 + self._ticking_sound: bui.Sound | None = None + # Get all textures used by our buttons preloading so hopefully # they'll be in place by the time we show them. for bdef in self._buttondefs: for bimg in bdef.imgdefs: bui.gettexture(bimg.tex) - # Wait for a master-server connection if need be. Otherwise we - # could error if called at the wrong time even with an internet - # connection, which is unintuitive. - wait_for_connectivity( - on_connected=bui.WeakCall(self._on_have_connectivity), - on_cancel=bui.WeakCall(self._back), + self._state = self.State.LOADING + + self._update_timer = bui.AppTimer( + 0.789, bui.WeakCall(self._update), repeat=True ) + self._update() - def _on_have_connectivity(self) -> None: - plus = bui.app.plus - assert plus is not None + def __del__(self) -> None: + if self._ticking_sound is not None: + self._ticking_sound.stop() + self._ticking_sound = None - # Sanity check; we need to be signed in. (we should not be - # allowed to get here if we aren't, but it could happen for - # fluke-ish reasons.) - if plus.accounts.primary is None: - bui.screenmessage( - bui.Lstr(resource='notSignedInErrorText'), color=(1, 0, 0) - ) - bui.getsound('error').play() - self._back() + def _update(self) -> None: + # No-op if our underlying widget is dead or on its way out. + if not self._root_widget or self._root_widget.transitioning_out: return - with plus.accounts.primary: - plus.cloud.send_message_cb( - bacommon.cloud.StoreQueryMessage(), - on_response=bui.WeakCall(self._on_store_query_response), + plus = bui.app.plus + + if plus is None or plus.accounts.primary is None: + self._update_state(self.State.NOT_SIGNED_IN) + return + + # Poll for relevant changes to the store or our account. + now = time.monotonic() + if not self._query_in_flight and now - self._last_query_time > 2.0: + self._last_query_time = now + self._query_in_flight = True + with plus.accounts.primary: + plus.cloud.send_message_cb( + bacommon.cloud.StoreQueryMessage(), + on_response=bui.WeakCall(self._on_store_query_response), + ) + + # Can't do much until we get a store state. + if self._last_query_response is None: + return + + # If we've got a gold-pass, just show that. No need to offer any + # other purchases. + if self._last_query_response.gold_pass: + self._update_state(self.State.HAVE_GOLD_PASS) + return + + # Ok we seem to be signed in and have store stuff we can show. + # Do that. + self._update_state(self.State.SHOWING_STORE) + + def _update_state(self, state: State) -> None: + + # We don't do much when state is unchanged. + if state is self._state: + # Update a few things in store mode though, such as token + # count. + if state is self.State.SHOWING_STORE: + self._update_store_state() + return + + # Ok, state is changing. Start by resetting to a blank slate. + self._token_count_widget = None + for widget in self._root_widget.get_children(): + if widget not in self._core_widgets: + widget.delete() + + # Build up new state. + if state is self.State.NOT_SIGNED_IN: + bui.textwidget( + edit=self._status_text, + color=(1, 0, 0), + text=bui.Lstr(resource='notSignedInErrorText'), ) + elif state is self.State.LOADING: + raise RuntimeError('Should never return to loading state.') + elif state is self.State.HAVE_GOLD_PASS: + bui.textwidget( + edit=self._status_text, + color=(0, 1, 0), + text=( + 'You have a Gold Pass.\n' + 'All token purchases are free.\n' + 'Enjoy!' + ), + ) + elif state is self.State.SHOWING_STORE: + assert self._last_query_response is not None + bui.textwidget(edit=self._status_text, text='') + self._build_store_for_response(self._last_query_response) + else: + # Make sure we handle all cases. + assert_never(state) + + self._state = state def _on_load_error(self) -> None: bui.textwidget( @@ -418,20 +506,19 @@ class GetTokensWindow(bui.Window): def _on_store_query_response( self, response: bacommon.cloud.StoreQueryResponse | Exception + ) -> None: + self._query_in_flight = False + if isinstance(response, bacommon.cloud.StoreQueryResponse): + self._last_query_response = response + # Hurry along any effects of this response. + self._update() + + def _build_store_for_response( + self, response: bacommon.cloud.StoreQueryResponse ) -> None: # pylint: disable=too-many-locals - plus = bui.app.plus - # If our message failed, just error and back out. - if isinstance(response, Exception): - logging.info('Store query failed.', exc_info=response) - - bui.screenmessage(bui.Lstr(resource='errorText'), color=(1, 0, 0)) - bui.getsound('error').play() - self._back() - return - bui.textwidget(edit=self._status_text, text='') xinset = 40 @@ -559,7 +646,7 @@ class GetTokensWindow(bui.Window): v_align='center', text='BombSquad\'s shiny new currency.', ) - _tnumtxt = bui.textwidget( + self._token_count_widget = bui.textwidget( parent=self._root_widget, position=(self._width - self._x_inset - 120.0, self._height - 48), color=(2.0, 0.7, 0.0), @@ -568,8 +655,12 @@ class GetTokensWindow(bui.Window): size=(0, 0), h_align='left', v_align='center', - text=str(response.tokens), + text='', ) + self._token_count = response.tokens + self._smooth_token_count = float(self._token_count) + self._smooth_update() # will set the text widget. + _tlabeltxt = bui.textwidget( parent=self._root_widget, position=(self._width - self._x_inset - 123.0, self._height - 48), @@ -592,15 +683,83 @@ class GetTokensWindow(bui.Window): # Looks like purchases will never work here. errmsg = ( 'Sorry, purchases are not available on this build.\n' - 'As a fallback, sign in to this account on another' - ' platform and make purchases from there.' + 'Try signing into your account on another platform' + ' and making purchases from there.' ) bui.screenmessage(errmsg, color=(1, 0.5, 0)) bui.getsound('error').play() return - print(f'WOULD PURCHASE {itemid}') + assert plus is not None + plus.purchase(itemid) + + def _update_store_state(self) -> None: + """Called to make minor updates to an already shown store.""" + assert self._token_count_widget is not None + assert self._last_query_response is not None + + self._token_count = self._last_query_response.tokens + + # Kick off new smooth update if need be. + assert self._smooth_token_count is not None + if ( + self._token_count != int(self._smooth_token_count) + and self._smooth_update_timer is None + ): + self._smooth_update_timer = bui.AppTimer( + 0.05, bui.WeakCall(self._smooth_update), repeat=True + ) + diff = abs(float(self._token_count) - self._smooth_token_count) + self._smooth_increase_speed = ( + diff / 100.0 + if diff >= 5000 + else ( + diff / 50.0 + if diff >= 1500 + else diff / 30.0 if diff >= 500 else diff / 15.0 + ) + ) + + def _smooth_update(self) -> None: + + # Stop if the count widget disappears. + if not self._token_count_widget: + self._smooth_update_timer = None + return + + finished = False + + # If we're going down, do it immediately. + assert self._smooth_token_count is not None + if int(self._smooth_token_count) >= self._token_count: + self._smooth_token_count = float(self._token_count) + finished = True + else: + # We're going up; start a sound if need be. + self._smooth_token_count = min( + self._smooth_token_count + 1.0 * self._smooth_increase_speed, + self._token_count, + ) + if int(self._smooth_token_count) >= self._token_count: + finished = True + self._smooth_token_count = float(self._token_count) + elif self._ticking_sound is None: + self._ticking_sound = bui.getsound('scoreIncrease') + self._ticking_sound.play() + + bui.textwidget( + edit=self._token_count_widget, + text=str(int(self._smooth_token_count)), + ) + + # If we've reached the target, kill the timer/sound/etc. + if finished: + self._smooth_update_timer = None + if self._ticking_sound is not None: + self._ticking_sound.stop() + self._ticking_sound = None + bui.getsound('cashRegister2').play() def _back(self) -> None: diff --git a/src/ballistica/base/platform/apple/base_platform_apple.cc b/src/ballistica/base/platform/apple/base_platform_apple.cc index 4d088ce1..11311fc2 100644 --- a/src/ballistica/base/platform/apple/base_platform_apple.cc +++ b/src/ballistica/base/platform/apple/base_platform_apple.cc @@ -41,12 +41,12 @@ void BasePlatformApple::RestorePurchases() { } void BasePlatformApple::PurchaseAck(const std::string& purchase, - const std::string& order_id) { + const std::string& order_id, bool valid) { #if BA_USE_STORE_KIT BallisticaKit::StoreKitContext::purchaseAck(purchase, order_id); // AppleUtils::PurchaseAck(purchase, order_id); #else - BasePlatform::PurchaseAck(purchase, order_id); + BasePlatform::PurchaseAck(purchase, order_id, valid); #endif } diff --git a/src/ballistica/base/platform/apple/base_platform_apple.h b/src/ballistica/base/platform/apple/base_platform_apple.h index 7d8c8864..de99262d 100644 --- a/src/ballistica/base/platform/apple/base_platform_apple.h +++ b/src/ballistica/base/platform/apple/base_platform_apple.h @@ -13,8 +13,8 @@ class BasePlatformApple : public BasePlatform { BasePlatformApple(); void DoPurchase(const std::string& item) override; void RestorePurchases() override; - void PurchaseAck(const std::string& purchase, - const std::string& order_id) override; + void PurchaseAck(const std::string& purchase, const std::string& order_id, + bool valid) override; void DoOpenURL(const std::string& url) override; auto OverlayWebBrowserIsSupported() -> bool override; void DoOverlayWebBrowserOpenURL(const std::string& url) override; diff --git a/src/ballistica/base/platform/base_platform.cc b/src/ballistica/base/platform/base_platform.cc index 7c226efb..e5dd0e4d 100644 --- a/src/ballistica/base/platform/base_platform.cc +++ b/src/ballistica/base/platform/base_platform.cc @@ -106,7 +106,7 @@ void BasePlatform::RestorePurchases() { } void BasePlatform::PurchaseAck(const std::string& purchase, - const std::string& order_id) { + const std::string& order_id, bool valid) { Log(LogLevel::kError, "PurchaseAck() unimplemented"); } diff --git a/src/ballistica/base/platform/base_platform.h b/src/ballistica/base/platform/base_platform.h index 2d864e1a..58aee1cb 100644 --- a/src/ballistica/base/platform/base_platform.h +++ b/src/ballistica/base/platform/base_platform.h @@ -52,9 +52,9 @@ class BasePlatform { /// Restore purchases (currently only relevant on Apple platforms). virtual void RestorePurchases(); - /// Purchase was ack'ed by the master-server (so can consume). + /// Purchase was ack'ed by the master-server (so can consume or cancel). virtual void PurchaseAck(const std::string& purchase, - const std::string& order_id); + const std::string& order_id, bool valid); #pragma mark ENVIRONMENT ------------------------------------------------------- diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 1e8ad083..b5e76fca 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -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 = 21919; +const int kEngineBuildNumber = 21928; const char* kEngineVersion = "1.7.36"; const int kEngineApiVersion = 8; diff --git a/tools/bacommon/cloud.py b/tools/bacommon/cloud.py index 40fee022..ec02e027 100644 --- a/tools/bacommon/cloud.py +++ b/tools/bacommon/cloud.py @@ -284,5 +284,7 @@ class StoreQueryResponse(Response): result: Annotated[Result, IOAttrs('r')] tokens: Annotated[int, IOAttrs('t')] + gold_pass: Annotated[bool, IOAttrs('g')] + available_purchases: Annotated[list[Purchase], IOAttrs('p')] token_info_url: Annotated[str, IOAttrs('tiu')] diff --git a/tools/efrotools/sync.py b/tools/efrotools/sync.py index 22fcc47b..aaf91a42 100644 --- a/tools/efrotools/sync.py +++ b/tools/efrotools/sync.py @@ -98,7 +98,10 @@ def run_standard_syncs( # Actual syncs require localconfig entries. if link_entry not in localconfig: - print(f'No link entry for {src_project}; skipping sync entry.') + print( + f'No link entry for {src_project}' + f' in project {projectroot}; skipping sync entry.' + ) continue src = Path(localconfig[link_entry], src_subpath) if verbose: