mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +08:00
more work on chests
This commit is contained in:
parent
05f09c94de
commit
d16698e35e
72
.efrocachemap
generated
72
.efrocachemap
generated
@ -4103,42 +4103,42 @@
|
||||
"build/assets/windows/Win32/ucrtbased.dll": "bfd1180c269d3950b76f35a63655e9e1",
|
||||
"build/assets/windows/Win32/vc_redist.x86.exe": "15a5f1f876503885adbdf5b3989b3718",
|
||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "50d25937dea753465f4c37093252a506",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "9379bbb7a0e05265618072ce54b5150b",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "31d6adcaabf9c6626bba3840cad8e887",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "b9eac18a217bc7688b2d9144b2d712f6",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e89c0ffde5d3e39aeb585544de2b5020",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "a265586bc3c0a3190ca43cd66bb786d1",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "bd5776295818b26d4933e0c95de5ccf5",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "202c243dea911c748673edebd01a6d27",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "80b9857bec34269d850fc0a196628ff1",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "1bf73ae24f6a33a1d8bffb901e655072",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "f81be586ef989a7a70d7d6db66e6d333",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "989eaa1a362d5584bca1c703f1fb297a",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "fc585782cef6148c70914988a0a6c4d6",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "7c51de6bbecaf69f9c447819891537ad",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "7eaae5174e50c2007af260ae6ca1db4c",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "daa74a12e1655dc73603dfcc7c14029f",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "144b0407bc4aa4fd889adeb9938f7c83",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "b546945362b7e71974acaf41ddd52c6e",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "144b0407bc4aa4fd889adeb9938f7c83",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "b546945362b7e71974acaf41ddd52c6e",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "f7a4426a032132569d5d61addd25932f",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "a8d2a7566260465abe9dd3cb75dcffc5",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "f7a4426a032132569d5d61addd25932f",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "a8d2a7566260465abe9dd3cb75dcffc5",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "f052e79cad083c718834345ef01015ca",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "5484ab93d479f69111fb2a83cafbf269",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "f052e79cad083c718834345ef01015ca",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "5484ab93d479f69111fb2a83cafbf269",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "cec1716fa0fd08cfb444b12fc3a1d90b",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "3a4f575fe91ac1944e6d5a2935b2e18d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "48ef32642a8de1aabb0533ce692f5344",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "06af8dc996eaa17fc01b3ddbaef704ad",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "45437fa0d848b76b77aeae9bf3792389",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "9b32bec0aff1d5b2a56b2548d33ae9f8",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "9bb774ea2805698e5fa47cf0e8367f8a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "57c81da4ae274d0694e470c61da13967",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "56e112f2611f640ef7bfea763fc0ea16",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "5e0cffe1c4d0df70f18d49ba9681cc72",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "4b8e5afb0166ad3d3116d04d494f9ec1",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "0285611c819eca94e4c2940a7a16c2b8",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e33e669704eb9545a5297fca0f7e28f2",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8485f8eff6706edb86e59ae6a5384f04",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "478942a23a7c1aca322ec1a3f891f7c7",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "af131198a42bceb8267bfbcbf27dd6a7",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "322b35f9163d234b268514b5c0d5b1c9",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "fb16e35043f457789acffad702d44a6a",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "de8ce2028178cf500e5e566d585ab7f5",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "2a8cb6b7dae73d61f6099d632bf65ea3",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "b1de7efc71e14c2dc90b7e174bb3c87a",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "2d41f6d86c37743f9816ca7cffe1d9d9",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "ae53c7ca3472750729b21e645a54b087",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "116735872e943dd1fa2c28784fdbdecc",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "c8c1f174ed35992eb71bf1ff22787f4e",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "67e1e5286f3fe64c9935e0e22d3fe443",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "c8c1f174ed35992eb71bf1ff22787f4e",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "67e1e5286f3fe64c9935e0e22d3fe443",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "c6f45e134e680f696df6d5f605fb8308",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "cfb87dbb40bfd0cdf4be9da5086265f8",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "c6f45e134e680f696df6d5f605fb8308",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "cfb87dbb40bfd0cdf4be9da5086265f8",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "b39713b9f3a9102fefff1f6d62a9fd82",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "1c2d42d75e8f975514b2e30f5602516d",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "b39713b9f3a9102fefff1f6d62a9fd82",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "1c2d42d75e8f975514b2e30f5602516d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "7d1035b51bf53dc9021d4d4123433b53",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "a299482d1e4b0991326809fee71f0705",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "cf2b630383875f27554c0260578f09c6",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "a19bfc04eff7a19f1719488c441c9408",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "58ee8e1778866d7024ebe47de325ccb9",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "9d5b9c3c508803b95f9a8e747bfc5921",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "8a0d29889da01c8aa1613d481dbfa151",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "568ff8fd799e4b2f51b939716d75e23c",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "06042d31df0ff9af96b99477162e2a91",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
### 1.7.37 (build 22139, api 9, 2024-12-19)
|
||||
### 1.7.37 (build 22140, api 9, 2024-12-21)
|
||||
- Bumping api version to 9. As you'll see below, there's some UI changes that
|
||||
will require a bit of work for any UI mods to adapt to. If your mods don't
|
||||
touch UI stuff at all you can simply bump your api version and call it a day.
|
||||
|
||||
@ -2,7 +2,7 @@ cpplint==2.0.0
|
||||
dmgbuild==1.6.2
|
||||
filelock==3.16.1
|
||||
furo==2024.8.6
|
||||
mypy==1.13.0
|
||||
mypy==1.14.0
|
||||
pbxproj==4.2.1
|
||||
pdoc==15.0.1
|
||||
pur==7.3.3
|
||||
|
||||
@ -378,6 +378,7 @@
|
||||
"ba_data/python/bauiv1lib/__pycache__/achievements.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/appinvite.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/characterpicker.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/chest.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/colorpicker.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/confirm.cpython-312.opt-1.pyc",
|
||||
@ -430,6 +431,7 @@
|
||||
"ba_data/python/bauiv1lib/achievements.py",
|
||||
"ba_data/python/bauiv1lib/appinvite.py",
|
||||
"ba_data/python/bauiv1lib/characterpicker.py",
|
||||
"ba_data/python/bauiv1lib/chest.py",
|
||||
"ba_data/python/bauiv1lib/colorpicker.py",
|
||||
"ba_data/python/bauiv1lib/config.py",
|
||||
"ba_data/python/bauiv1lib/confirm.py",
|
||||
|
||||
@ -347,6 +347,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/achievements.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/appinvite.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/characterpicker.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/chest.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/colorpicker.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/config.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/confirm.py \
|
||||
@ -627,6 +628,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/achievements.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/appinvite.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/characterpicker.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/chest.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/colorpicker.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/confirm.cpython-312.opt-1.pyc \
|
||||
|
||||
@ -134,6 +134,7 @@ from babase._apputils import (
|
||||
garbage_collect,
|
||||
get_remote_app_name,
|
||||
AppHealthMonitor,
|
||||
utc_now_cloud,
|
||||
)
|
||||
from babase._cloud import CloudSubscription
|
||||
from babase._devconsole import (
|
||||
@ -360,6 +361,7 @@ __all__ = [
|
||||
'update_internal_logger_levels',
|
||||
'user_agent_string',
|
||||
'user_ran_commands',
|
||||
'utc_now_cloud',
|
||||
'utf8_all',
|
||||
'Vec3',
|
||||
'vec3validate',
|
||||
|
||||
@ -258,6 +258,12 @@ class App:
|
||||
"""
|
||||
return _babase.app_is_active()
|
||||
|
||||
@property
|
||||
def mode(self) -> AppMode | None:
|
||||
"""The app's current mode."""
|
||||
assert _babase.in_logic_thread()
|
||||
return self._mode
|
||||
|
||||
@property
|
||||
def asyncio_loop(self) -> asyncio.AbstractEventLoop:
|
||||
"""The logic thread's asyncio event loop.
|
||||
|
||||
@ -11,6 +11,7 @@ from functools import partial
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from efro.util import utc_now
|
||||
from efro.logging import LogLevel
|
||||
from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json
|
||||
|
||||
@ -18,11 +19,21 @@ import _babase
|
||||
from babase._appsubsystem import AppSubsystem
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import datetime
|
||||
from typing import Any, TextIO, Callable
|
||||
|
||||
import babase
|
||||
|
||||
|
||||
def utc_now_cloud() -> datetime.datetime:
|
||||
"""Returns estimated utc time regardless of local clock settings.
|
||||
|
||||
Applies offsets pulled from server communication/etc.
|
||||
"""
|
||||
# FIXME - do something smart here.
|
||||
return utc_now()
|
||||
|
||||
|
||||
def is_browser_likely_available() -> bool:
|
||||
"""Return whether a browser likely exists on the current device.
|
||||
|
||||
|
||||
@ -156,6 +156,9 @@ class _WeakCall:
|
||||
to wrap them in weakrefs manually if desired.
|
||||
"""
|
||||
|
||||
# Optimize performance a bit; we shouldn't need to be super dynamic.
|
||||
__slots__ = ['_call', '_args', '_keywds']
|
||||
|
||||
_did_invalid_call_warning = False
|
||||
|
||||
def __init__(self, *args: Any, **keywds: Any) -> None:
|
||||
@ -175,7 +178,7 @@ class _WeakCall:
|
||||
' to avoid this warning.',
|
||||
stack_info=True,
|
||||
)
|
||||
self._did_invalid_call_warning = True
|
||||
type(self)._did_invalid_call_warning = True
|
||||
self._call = args[0]
|
||||
self._args = args[1:]
|
||||
self._keywds = keywds
|
||||
@ -214,6 +217,9 @@ class _Call:
|
||||
without keeping its object alive.
|
||||
"""
|
||||
|
||||
# Optimize performance a bit; we shouldn't need to be super dynamic.
|
||||
__slots__ = ['_call', '_args', '_keywds']
|
||||
|
||||
def __init__(self, *args: Any, **keywds: Any):
|
||||
"""Instantiate a Call.
|
||||
|
||||
@ -280,6 +286,9 @@ class WeakMethod:
|
||||
free to die. If called with a dead target, is simply a no-op.
|
||||
"""
|
||||
|
||||
# Optimize performance a bit; we shouldn't need to be super dynamic.
|
||||
__slots__ = ['_func', '_obj']
|
||||
|
||||
def __init__(self, call: types.MethodType):
|
||||
assert isinstance(call, types.MethodType)
|
||||
self._func = call.__func__
|
||||
|
||||
@ -15,10 +15,11 @@ import bauiv1
|
||||
import _baclassic
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
from typing import Callable, Any, Literal
|
||||
|
||||
from efro.call import CallbackRegistration
|
||||
import bacommon.cloud
|
||||
from bauiv1lib.chest import ChestWindow
|
||||
|
||||
|
||||
# ba_meta export babase.AppMode
|
||||
@ -481,5 +482,42 @@ class ClassicAppMode(babase.AppMode):
|
||||
)
|
||||
|
||||
def _root_ui_chest_slot_pressed(self, index: int) -> None:
|
||||
print(f'CHEST {index} PRESSED')
|
||||
babase.screenmessage('UNDER CONSTRUCTION.')
|
||||
from bauiv1lib.chest import (
|
||||
ChestWindow0,
|
||||
ChestWindow1,
|
||||
ChestWindow2,
|
||||
ChestWindow3,
|
||||
)
|
||||
from bauiv1lib.connectivity import wait_for_connectivity
|
||||
|
||||
widgetid: Literal[
|
||||
'chest_0_button',
|
||||
'chest_1_button',
|
||||
'chest_2_button',
|
||||
'chest_3_button',
|
||||
]
|
||||
winclass: type[ChestWindow]
|
||||
if index == 0:
|
||||
widgetid = 'chest_0_button'
|
||||
winclass = ChestWindow0
|
||||
elif index == 1:
|
||||
widgetid = 'chest_1_button'
|
||||
winclass = ChestWindow1
|
||||
elif index == 2:
|
||||
widgetid = 'chest_2_button'
|
||||
winclass = ChestWindow2
|
||||
elif index == 3:
|
||||
widgetid = 'chest_3_button'
|
||||
winclass = ChestWindow3
|
||||
else:
|
||||
raise RuntimeError(f'Invalid index {index}')
|
||||
|
||||
wait_for_connectivity(
|
||||
on_connected=lambda: self._auxiliary_window_nav(
|
||||
win_type=winclass,
|
||||
win_create_call=lambda: winclass(
|
||||
index=index,
|
||||
origin_widget=bauiv1.get_special_widget(widgetid),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
@ -53,7 +53,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 22139
|
||||
TARGET_BALLISTICA_BUILD = 22140
|
||||
TARGET_BALLISTICA_VERSION = '1.7.37'
|
||||
|
||||
|
||||
|
||||
@ -134,6 +134,24 @@ class CloudSubsystem(babase.AppSubsystem):
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSChestInfoMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSChestInfoResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSChestActionMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSChestActionResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: Message,
|
||||
|
||||
@ -96,6 +96,7 @@ from babase import (
|
||||
timestring,
|
||||
UIScale,
|
||||
unlock_all_input,
|
||||
utc_now_cloud,
|
||||
WeakCall,
|
||||
workspaces_in_use,
|
||||
)
|
||||
@ -238,6 +239,7 @@ __all__ = [
|
||||
'UIScale',
|
||||
'UIV1AppSubsystem',
|
||||
'unlock_all_input',
|
||||
'utc_now_cloud',
|
||||
'WeakCall',
|
||||
'widget',
|
||||
'Widget',
|
||||
|
||||
348
src/assets/ba_data/python/bauiv1lib/chest.py
Normal file
348
src/assets/ba_data/python/bauiv1lib/chest.py
Normal file
@ -0,0 +1,348 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Provides chest related ui."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
import bacommon.cloud
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class ChestWindow(bui.MainWindow):
|
||||
"""Allows operations on a chest."""
|
||||
|
||||
def __del__(self) -> None:
|
||||
print('~ChestWindow()')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
index: int,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
print('ChestWindow()')
|
||||
|
||||
self._index = index
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 1050 if uiscale is bui.UIScale.SMALL else 850
|
||||
self._height = (
|
||||
500
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 500 if uiscale is bui.UIScale.MEDIUM else 500
|
||||
)
|
||||
self._xoffs = 70 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._yoffs = -42 if uiscale is bui.UIScale.SMALL else -25
|
||||
self._action_in_flight = False
|
||||
self._open_now_button: bui.Widget | None = None
|
||||
self._watch_ad_button: bui.Widget | None = None
|
||||
|
||||
# The set of widgets we keep when doing a clear.
|
||||
self._core_widgets: list[bui.Widget] = []
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
toolbar_visibility='menu_full',
|
||||
scale=(
|
||||
1.55
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.9
|
||||
),
|
||||
stack_offset=(
|
||||
(0, 0)
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (0, 15) if uiscale is bui.UIScale.MEDIUM else (0, 0)
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._core_widgets.append(
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, self._height - 45 + self._yoffs),
|
||||
size=(self._width, 25),
|
||||
text=f'Chest #{self._index + 1}',
|
||||
color=bui.app.ui_v1.title_color,
|
||||
maxwidth=150.0,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._xoffs + 50, self._height - 55 + self._yoffs),
|
||||
size=(60, 55),
|
||||
scale=0.8,
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
extra_touch_border_scale=2.0,
|
||||
autoselect=True,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
self._core_widgets.append(btn)
|
||||
|
||||
self._infotext = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 200 + self._yoffs),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(resource='loadingText'),
|
||||
maxwidth=700,
|
||||
scale=0.7,
|
||||
color=(0.6, 0.5, 0.6),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
self._core_widgets.append(self._infotext)
|
||||
|
||||
plus = bui.app.plus
|
||||
if plus is None:
|
||||
self._error('Plus feature-set is not present.')
|
||||
return
|
||||
|
||||
if plus.accounts.primary is None:
|
||||
self._error(bui.Lstr(resource='notSignedInText'))
|
||||
return
|
||||
|
||||
# Start by showing info/options for our target chest. Note that
|
||||
# we always ask the server for these values even though we may
|
||||
# have them through our appmode subscription which updates the
|
||||
# chest UI. This is because the wait_for_connectivity()
|
||||
# mechanism will often bring our window up a split second before
|
||||
# the chest subscription receives its first values which would
|
||||
# lead us to incorrectly think there is no chest there. If we
|
||||
# want to optimize this in the future we could perhaps use local
|
||||
# values only if there is a chest present in them.
|
||||
assert not self._action_in_flight
|
||||
self._action_in_flight = True
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSChestInfoMessage(chest_id=str(self._index)),
|
||||
on_response=bui.WeakCall(self._on_chest_info_response),
|
||||
)
|
||||
|
||||
def _on_chest_info_response(
|
||||
self, response: bacommon.cloud.BSChestInfoResponse | Exception
|
||||
) -> None:
|
||||
assert self._action_in_flight # Should be us.
|
||||
self._action_in_flight = False
|
||||
|
||||
if isinstance(response, Exception):
|
||||
self._error(
|
||||
bui.Lstr(resource='internal.unavailableNoConnectionText')
|
||||
)
|
||||
return
|
||||
|
||||
if response.chest is None:
|
||||
self._error('Would show general info about chests.')
|
||||
return
|
||||
|
||||
self.show_chest_actions(response.chest)
|
||||
|
||||
def _on_chest_action_response(
|
||||
self, response: bacommon.cloud.BSChestActionResponse | Exception
|
||||
) -> None:
|
||||
assert self._action_in_flight # Should be us.
|
||||
self._action_in_flight = False
|
||||
|
||||
# Communication/local error:
|
||||
if isinstance(response, Exception):
|
||||
self._error(
|
||||
bui.Lstr(resource='internal.unavailableNoConnectionText')
|
||||
)
|
||||
return
|
||||
|
||||
# Server-side error:
|
||||
if response.error is not None:
|
||||
self._error(bui.Lstr(translate=('serverResponses', response.error)))
|
||||
return
|
||||
|
||||
# If there's contents listed in the response, show them.
|
||||
if response.contents is not None:
|
||||
print('WOULD SHOW CONTENTS:', response.contents)
|
||||
else:
|
||||
# Otherwise we're done here; just close out our UI.
|
||||
self.main_window_back()
|
||||
|
||||
def show_chest_actions(
|
||||
self, chest: bacommon.cloud.BSChestInfoResponse.Chest
|
||||
) -> None:
|
||||
"""Show state for our chest."""
|
||||
# pylint: disable=cyclic-import
|
||||
from baclassic import ClassicAppMode
|
||||
|
||||
# We expect to be run under classic.
|
||||
mode = bui.app.mode
|
||||
if not isinstance(mode, ClassicAppMode):
|
||||
self._error('Classic app mode not active.')
|
||||
return
|
||||
|
||||
now = bui.utc_now_cloud()
|
||||
secs_till_open = max(0.0, (chest.unlock_time - now).total_seconds())
|
||||
tstr = bui.timestring(secs_till_open, centi=False)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 120 + self._yoffs),
|
||||
size=(0, 0),
|
||||
text=tstr,
|
||||
maxwidth=700,
|
||||
scale=0.7,
|
||||
color=(0.6, 0.5, 0.6),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
self._open_now_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width * 0.5 - 200,
|
||||
self._height - 250 + self._yoffs,
|
||||
),
|
||||
size=(150, 100),
|
||||
label=f'OPEN NOW FOR {chest.unlock_tokens} TOKENS',
|
||||
button_type='square',
|
||||
autoselect=True,
|
||||
on_activate_call=bui.WeakCall(
|
||||
self._open_now_press, chest.unlock_tokens
|
||||
),
|
||||
)
|
||||
|
||||
self._watch_ad_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width * 0.5 + 50,
|
||||
self._height - 250 + self._yoffs,
|
||||
),
|
||||
size=(150, 100),
|
||||
label='WATCH AN AD TO REDUCE WAIT',
|
||||
button_type='square',
|
||||
autoselect=True,
|
||||
on_activate_call=bui.WeakCall(self._watch_ad_press),
|
||||
)
|
||||
bui.textwidget(edit=self._infotext, text='')
|
||||
|
||||
def _open_now_press(self, token_payment: int) -> None:
|
||||
|
||||
# Allow only one in-flight action at once.
|
||||
if self._action_in_flight:
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='pleaseWaitText'), color=(1, 0, 0)
|
||||
)
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
if plus.accounts.primary is None:
|
||||
self._error(bui.Lstr(resource='notSignedInText'))
|
||||
return
|
||||
|
||||
self._action_in_flight = True
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSChestActionMessage(
|
||||
chest_id=str(self._index),
|
||||
action=bacommon.cloud.BSChestActionMessage.Action.UNLOCK,
|
||||
token_payment=token_payment,
|
||||
),
|
||||
on_response=bui.WeakCall(self._on_chest_action_response),
|
||||
)
|
||||
|
||||
# Convey that something is in progress.
|
||||
if self._open_now_button:
|
||||
bui.buttonwidget(edit=self._open_now_button, label='...')
|
||||
|
||||
def _watch_ad_press(self) -> None:
|
||||
|
||||
# Allow only one in-flight action at once.
|
||||
if self._action_in_flight:
|
||||
bui.screenmessage('ERR', color=(1, 0, 0))
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
if plus.accounts.primary is None:
|
||||
self._error(bui.Lstr(resource='notSignedInText'))
|
||||
return
|
||||
|
||||
self._action_in_flight = True
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSChestActionMessage(
|
||||
chest_id=str(self._index),
|
||||
action=bacommon.cloud.BSChestActionMessage.Action.AD,
|
||||
token_payment=0,
|
||||
),
|
||||
on_response=bui.WeakCall(self._on_chest_action_response),
|
||||
)
|
||||
|
||||
# Convey that something is in progress.
|
||||
if self._watch_ad_button:
|
||||
bui.buttonwidget(edit=self._watch_ad_button, label='...')
|
||||
|
||||
def _reset(self) -> None:
|
||||
"""Clear all non-permanent widgets."""
|
||||
for widget in self._root_widget.get_children():
|
||||
if widget not in self._core_widgets:
|
||||
widget.delete()
|
||||
|
||||
def _error(self, msg: str | bui.Lstr) -> None:
|
||||
"""Put ourself in an error state with a visible error message."""
|
||||
self._reset()
|
||||
bui.textwidget(edit=self._infotext, text=msg, color=(1, 0, 0))
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
# Pull anything we need from self out here; if we do it in the
|
||||
# lambda we keep self alive which is bad.
|
||||
index = self._index
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
index=index, transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Slight hack: we define different classes for our different chest slots
|
||||
# so that the default UI behavior is to replace each other when
|
||||
# different ones are pressed. If they are all the same class then the
|
||||
# default behavior for such presses is to toggle the existing one back
|
||||
# off.
|
||||
|
||||
|
||||
class ChestWindow0(ChestWindow):
|
||||
"""Child class of ChestWindow for slighty hackish reasons."""
|
||||
|
||||
|
||||
class ChestWindow1(ChestWindow):
|
||||
"""Child class of ChestWindow for slighty hackish reasons."""
|
||||
|
||||
|
||||
class ChestWindow2(ChestWindow):
|
||||
"""Child class of ChestWindow for slighty hackish reasons."""
|
||||
|
||||
|
||||
class ChestWindow3(ChestWindow):
|
||||
"""Child class of ChestWindow for slighty hackish reasons."""
|
||||
@ -28,7 +28,7 @@ class InventoryWindow(bui.MainWindow):
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 530 if uiscale is bui.UIScale.MEDIUM else 600
|
||||
)
|
||||
x_offs = 70 if uiscale is bui.UIScale.SMALL else 0
|
||||
xoffs = 70 if uiscale is bui.UIScale.SMALL else 0
|
||||
yoffs = -45 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
@ -71,7 +71,7 @@ class InventoryWindow(bui.MainWindow):
|
||||
else:
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(x_offs + 50, height - 55 + yoffs),
|
||||
position=(xoffs + 50, height - 55 + yoffs),
|
||||
size=(60, 55),
|
||||
scale=0.8,
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
|
||||
@ -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 = 22139;
|
||||
const int kEngineBuildNumber = 22140;
|
||||
const char* kEngineVersion = "1.7.37";
|
||||
const int kEngineApiVersion = 9;
|
||||
|
||||
|
||||
@ -2607,6 +2607,10 @@ static PyMethodDef PyGetSpecialWidgetDef = {
|
||||
" 'trophy_meter',"
|
||||
" 'level_meter',"
|
||||
" 'overlay_stack',"
|
||||
" 'chest_0_button',"
|
||||
" 'chest_1_button',"
|
||||
" 'chest_2_button',"
|
||||
" 'chest_3_button',"
|
||||
" ]) -> bauiv1.Widget\n"
|
||||
"\n"
|
||||
"(internal)",
|
||||
|
||||
@ -1335,6 +1335,14 @@ auto RootWidget::GetSpecialWidget(const std::string& s) const -> Widget* {
|
||||
return level_meter_button_ ? level_meter_button_->widget.get() : nullptr;
|
||||
} else if (s == "overlay_stack") {
|
||||
return overlay_stack_widget_;
|
||||
} else if (s == "chest_0_button") {
|
||||
return chest_0_button_->widget.get();
|
||||
} else if (s == "chest_1_button") {
|
||||
return chest_1_button_->widget.get();
|
||||
} else if (s == "chest_2_button") {
|
||||
return chest_2_button_->widget.get();
|
||||
} else if (s == "chest_3_button") {
|
||||
return chest_3_button_->widget.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -1462,7 +1470,7 @@ void RootWidget::SetChests(const std::string& chest_0_appearance,
|
||||
assert(b);
|
||||
if (appearance == "") {
|
||||
b->widget->set_color(0.473f, 0.44f, 0.583f);
|
||||
b->widget->set_opacity(0.5f);
|
||||
b->widget->set_opacity(have_chests ? 1.0f : 0.5f);
|
||||
b->width = b->height = 80.0f;
|
||||
b->y = have_chests ? 44.0f : 0.0f;
|
||||
{
|
||||
|
||||
@ -347,8 +347,6 @@ class BSClassicAccountLiveData:
|
||||
BSClassicChestAppearance,
|
||||
IOAttrs('a', enum_fallback=BSClassicChestAppearance.UNKNOWN),
|
||||
]
|
||||
create_time: Annotated[datetime.datetime, IOAttrs('c')]
|
||||
unlock_tokens: Annotated[int, IOAttrs('tk')]
|
||||
unlock_time: Annotated[datetime.datetime, IOAttrs('t')]
|
||||
ad_allow_time: Annotated[datetime.datetime | None, IOAttrs('at')]
|
||||
|
||||
@ -433,6 +431,85 @@ class BSInboxRequestResponse(Response):
|
||||
error: Annotated[str | None, IOAttrs('e')] = None
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSChestInfoMessage(Message):
|
||||
"""Request info about a chest."""
|
||||
|
||||
chest_id: Annotated[str, IOAttrs('i')]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [BSChestInfoResponse]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSChestInfoResponse(Response):
|
||||
"""Here's that inbox contents you asked for, boss."""
|
||||
|
||||
@dataclass
|
||||
class Chest:
|
||||
"""A lovely chest."""
|
||||
|
||||
appearance: Annotated[
|
||||
BSClassicChestAppearance,
|
||||
IOAttrs('a', enum_fallback=BSClassicChestAppearance.UNKNOWN),
|
||||
]
|
||||
|
||||
# How much to unlock *now*.
|
||||
unlock_tokens: Annotated[int, IOAttrs('tk')]
|
||||
|
||||
# When unlocks on its own.
|
||||
unlock_time: Annotated[datetime.datetime, IOAttrs('t')]
|
||||
|
||||
# Are ads allowed now?
|
||||
ad_allow: Annotated[bool, IOAttrs('aa')]
|
||||
|
||||
chest: Annotated[Chest | None, IOAttrs('c')]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSChestActionMessage(Message):
|
||||
"""Request action about a chest."""
|
||||
|
||||
class Action(Enum):
|
||||
"""Types of actions we can request."""
|
||||
|
||||
# Unlocking (for free or with tokens).
|
||||
UNLOCK = 'u'
|
||||
|
||||
# Watched an ad to reduce wait.
|
||||
AD = 'ad'
|
||||
|
||||
action: Annotated[Action, IOAttrs('a')]
|
||||
|
||||
# Tokens we are paying (only applies to unlock).
|
||||
token_payment: Annotated[int, IOAttrs('t')]
|
||||
|
||||
chest_id: Annotated[str, IOAttrs('i')]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [BSChestActionResponse]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSChestActionResponse(Response):
|
||||
"""Here's the results of that action you asked for, boss."""
|
||||
|
||||
# If present, signifies the chest has been opened and we should show
|
||||
# the user this stuff that was in it.
|
||||
contents: Annotated[list[str] | None, IOAttrs('c')] = None
|
||||
|
||||
# Printable error if something goes wrong.
|
||||
error: Annotated[str | None, IOAttrs('e')] = None
|
||||
|
||||
|
||||
class BSInboxEntryProcessType(Enum):
|
||||
"""Types of processing we can ask for."""
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user