mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-05 06:53:18 +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/ucrtbased.dll": "bfd1180c269d3950b76f35a63655e9e1",
|
||||||
"build/assets/windows/Win32/vc_redist.x86.exe": "15a5f1f876503885adbdf5b3989b3718",
|
"build/assets/windows/Win32/vc_redist.x86.exe": "15a5f1f876503885adbdf5b3989b3718",
|
||||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "50d25937dea753465f4c37093252a506",
|
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "56e112f2611f640ef7bfea763fc0ea16",
|
||||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "9379bbb7a0e05265618072ce54b5150b",
|
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "5e0cffe1c4d0df70f18d49ba9681cc72",
|
||||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "31d6adcaabf9c6626bba3840cad8e887",
|
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "4b8e5afb0166ad3d3116d04d494f9ec1",
|
||||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "b9eac18a217bc7688b2d9144b2d712f6",
|
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "0285611c819eca94e4c2940a7a16c2b8",
|
||||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e89c0ffde5d3e39aeb585544de2b5020",
|
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e33e669704eb9545a5297fca0f7e28f2",
|
||||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "a265586bc3c0a3190ca43cd66bb786d1",
|
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8485f8eff6706edb86e59ae6a5384f04",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "bd5776295818b26d4933e0c95de5ccf5",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "478942a23a7c1aca322ec1a3f891f7c7",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "202c243dea911c748673edebd01a6d27",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "af131198a42bceb8267bfbcbf27dd6a7",
|
||||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "80b9857bec34269d850fc0a196628ff1",
|
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "322b35f9163d234b268514b5c0d5b1c9",
|
||||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "1bf73ae24f6a33a1d8bffb901e655072",
|
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "fb16e35043f457789acffad702d44a6a",
|
||||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "f81be586ef989a7a70d7d6db66e6d333",
|
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "de8ce2028178cf500e5e566d585ab7f5",
|
||||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "989eaa1a362d5584bca1c703f1fb297a",
|
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "2a8cb6b7dae73d61f6099d632bf65ea3",
|
||||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "fc585782cef6148c70914988a0a6c4d6",
|
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "b1de7efc71e14c2dc90b7e174bb3c87a",
|
||||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "7c51de6bbecaf69f9c447819891537ad",
|
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "2d41f6d86c37743f9816ca7cffe1d9d9",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "7eaae5174e50c2007af260ae6ca1db4c",
|
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "ae53c7ca3472750729b21e645a54b087",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "daa74a12e1655dc73603dfcc7c14029f",
|
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "116735872e943dd1fa2c28784fdbdecc",
|
||||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "144b0407bc4aa4fd889adeb9938f7c83",
|
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "c8c1f174ed35992eb71bf1ff22787f4e",
|
||||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "b546945362b7e71974acaf41ddd52c6e",
|
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "67e1e5286f3fe64c9935e0e22d3fe443",
|
||||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "144b0407bc4aa4fd889adeb9938f7c83",
|
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "c8c1f174ed35992eb71bf1ff22787f4e",
|
||||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "b546945362b7e71974acaf41ddd52c6e",
|
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "67e1e5286f3fe64c9935e0e22d3fe443",
|
||||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "f7a4426a032132569d5d61addd25932f",
|
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "c6f45e134e680f696df6d5f605fb8308",
|
||||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "a8d2a7566260465abe9dd3cb75dcffc5",
|
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "cfb87dbb40bfd0cdf4be9da5086265f8",
|
||||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "f7a4426a032132569d5d61addd25932f",
|
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "c6f45e134e680f696df6d5f605fb8308",
|
||||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "a8d2a7566260465abe9dd3cb75dcffc5",
|
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "cfb87dbb40bfd0cdf4be9da5086265f8",
|
||||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "f052e79cad083c718834345ef01015ca",
|
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "b39713b9f3a9102fefff1f6d62a9fd82",
|
||||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "5484ab93d479f69111fb2a83cafbf269",
|
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "1c2d42d75e8f975514b2e30f5602516d",
|
||||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "f052e79cad083c718834345ef01015ca",
|
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "b39713b9f3a9102fefff1f6d62a9fd82",
|
||||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "5484ab93d479f69111fb2a83cafbf269",
|
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "1c2d42d75e8f975514b2e30f5602516d",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "cec1716fa0fd08cfb444b12fc3a1d90b",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "7d1035b51bf53dc9021d4d4123433b53",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "3a4f575fe91ac1944e6d5a2935b2e18d",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "a299482d1e4b0991326809fee71f0705",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "48ef32642a8de1aabb0533ce692f5344",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "cf2b630383875f27554c0260578f09c6",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "06af8dc996eaa17fc01b3ddbaef704ad",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "a19bfc04eff7a19f1719488c441c9408",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "45437fa0d848b76b77aeae9bf3792389",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "58ee8e1778866d7024ebe47de325ccb9",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "9b32bec0aff1d5b2a56b2548d33ae9f8",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "9d5b9c3c508803b95f9a8e747bfc5921",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "9bb774ea2805698e5fa47cf0e8367f8a",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "8a0d29889da01c8aa1613d481dbfa151",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "57c81da4ae274d0694e470c61da13967",
|
"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/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad",
|
"src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "06042d31df0ff9af96b99477162e2a91",
|
"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
|
- 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
|
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.
|
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
|
dmgbuild==1.6.2
|
||||||
filelock==3.16.1
|
filelock==3.16.1
|
||||||
furo==2024.8.6
|
furo==2024.8.6
|
||||||
mypy==1.13.0
|
mypy==1.14.0
|
||||||
pbxproj==4.2.1
|
pbxproj==4.2.1
|
||||||
pdoc==15.0.1
|
pdoc==15.0.1
|
||||||
pur==7.3.3
|
pur==7.3.3
|
||||||
|
|||||||
@ -378,6 +378,7 @@
|
|||||||
"ba_data/python/bauiv1lib/__pycache__/achievements.cpython-312.opt-1.pyc",
|
"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__/appinvite.cpython-312.opt-1.pyc",
|
||||||
"ba_data/python/bauiv1lib/__pycache__/characterpicker.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__/colorpicker.cpython-312.opt-1.pyc",
|
||||||
"ba_data/python/bauiv1lib/__pycache__/config.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",
|
"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/achievements.py",
|
||||||
"ba_data/python/bauiv1lib/appinvite.py",
|
"ba_data/python/bauiv1lib/appinvite.py",
|
||||||
"ba_data/python/bauiv1lib/characterpicker.py",
|
"ba_data/python/bauiv1lib/characterpicker.py",
|
||||||
|
"ba_data/python/bauiv1lib/chest.py",
|
||||||
"ba_data/python/bauiv1lib/colorpicker.py",
|
"ba_data/python/bauiv1lib/colorpicker.py",
|
||||||
"ba_data/python/bauiv1lib/config.py",
|
"ba_data/python/bauiv1lib/config.py",
|
||||||
"ba_data/python/bauiv1lib/confirm.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/achievements.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/appinvite.py \
|
$(BUILD_DIR)/ba_data/python/bauiv1lib/appinvite.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/characterpicker.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/colorpicker.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/config.py \
|
$(BUILD_DIR)/ba_data/python/bauiv1lib/config.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/confirm.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__/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__/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__/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__/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__/config.cpython-312.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/confirm.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,
|
garbage_collect,
|
||||||
get_remote_app_name,
|
get_remote_app_name,
|
||||||
AppHealthMonitor,
|
AppHealthMonitor,
|
||||||
|
utc_now_cloud,
|
||||||
)
|
)
|
||||||
from babase._cloud import CloudSubscription
|
from babase._cloud import CloudSubscription
|
||||||
from babase._devconsole import (
|
from babase._devconsole import (
|
||||||
@ -360,6 +361,7 @@ __all__ = [
|
|||||||
'update_internal_logger_levels',
|
'update_internal_logger_levels',
|
||||||
'user_agent_string',
|
'user_agent_string',
|
||||||
'user_ran_commands',
|
'user_ran_commands',
|
||||||
|
'utc_now_cloud',
|
||||||
'utf8_all',
|
'utf8_all',
|
||||||
'Vec3',
|
'Vec3',
|
||||||
'vec3validate',
|
'vec3validate',
|
||||||
|
|||||||
@ -258,6 +258,12 @@ class App:
|
|||||||
"""
|
"""
|
||||||
return _babase.app_is_active()
|
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
|
@property
|
||||||
def asyncio_loop(self) -> asyncio.AbstractEventLoop:
|
def asyncio_loop(self) -> asyncio.AbstractEventLoop:
|
||||||
"""The logic thread's asyncio event loop.
|
"""The logic thread's asyncio event loop.
|
||||||
|
|||||||
@ -11,6 +11,7 @@ from functools import partial
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import TYPE_CHECKING, override
|
from typing import TYPE_CHECKING, override
|
||||||
|
|
||||||
|
from efro.util import utc_now
|
||||||
from efro.logging import LogLevel
|
from efro.logging import LogLevel
|
||||||
from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json
|
from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json
|
||||||
|
|
||||||
@ -18,11 +19,21 @@ import _babase
|
|||||||
from babase._appsubsystem import AppSubsystem
|
from babase._appsubsystem import AppSubsystem
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
import datetime
|
||||||
from typing import Any, TextIO, Callable
|
from typing import Any, TextIO, Callable
|
||||||
|
|
||||||
import babase
|
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:
|
def is_browser_likely_available() -> bool:
|
||||||
"""Return whether a browser likely exists on the current device.
|
"""Return whether a browser likely exists on the current device.
|
||||||
|
|
||||||
|
|||||||
@ -156,6 +156,9 @@ class _WeakCall:
|
|||||||
to wrap them in weakrefs manually if desired.
|
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
|
_did_invalid_call_warning = False
|
||||||
|
|
||||||
def __init__(self, *args: Any, **keywds: Any) -> None:
|
def __init__(self, *args: Any, **keywds: Any) -> None:
|
||||||
@ -175,7 +178,7 @@ class _WeakCall:
|
|||||||
' to avoid this warning.',
|
' to avoid this warning.',
|
||||||
stack_info=True,
|
stack_info=True,
|
||||||
)
|
)
|
||||||
self._did_invalid_call_warning = True
|
type(self)._did_invalid_call_warning = True
|
||||||
self._call = args[0]
|
self._call = args[0]
|
||||||
self._args = args[1:]
|
self._args = args[1:]
|
||||||
self._keywds = keywds
|
self._keywds = keywds
|
||||||
@ -214,6 +217,9 @@ class _Call:
|
|||||||
without keeping its object alive.
|
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):
|
def __init__(self, *args: Any, **keywds: Any):
|
||||||
"""Instantiate a Call.
|
"""Instantiate a Call.
|
||||||
|
|
||||||
@ -280,6 +286,9 @@ class WeakMethod:
|
|||||||
free to die. If called with a dead target, is simply a no-op.
|
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):
|
def __init__(self, call: types.MethodType):
|
||||||
assert isinstance(call, types.MethodType)
|
assert isinstance(call, types.MethodType)
|
||||||
self._func = call.__func__
|
self._func = call.__func__
|
||||||
|
|||||||
@ -15,10 +15,11 @@ import bauiv1
|
|||||||
import _baclassic
|
import _baclassic
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Callable, Any
|
from typing import Callable, Any, Literal
|
||||||
|
|
||||||
from efro.call import CallbackRegistration
|
from efro.call import CallbackRegistration
|
||||||
import bacommon.cloud
|
import bacommon.cloud
|
||||||
|
from bauiv1lib.chest import ChestWindow
|
||||||
|
|
||||||
|
|
||||||
# ba_meta export babase.AppMode
|
# ba_meta export babase.AppMode
|
||||||
@ -481,5 +482,42 @@ class ClassicAppMode(babase.AppMode):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _root_ui_chest_slot_pressed(self, index: int) -> None:
|
def _root_ui_chest_slot_pressed(self, index: int) -> None:
|
||||||
print(f'CHEST {index} PRESSED')
|
from bauiv1lib.chest import (
|
||||||
babase.screenmessage('UNDER CONSTRUCTION.')
|
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
|
# Build number and version of the ballistica binary we expect to be
|
||||||
# using.
|
# using.
|
||||||
TARGET_BALLISTICA_BUILD = 22139
|
TARGET_BALLISTICA_BUILD = 22140
|
||||||
TARGET_BALLISTICA_VERSION = '1.7.37'
|
TARGET_BALLISTICA_VERSION = '1.7.37'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -134,6 +134,24 @@ class CloudSubsystem(babase.AppSubsystem):
|
|||||||
],
|
],
|
||||||
) -> None: ...
|
) -> 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(
|
def send_message_cb(
|
||||||
self,
|
self,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
|
|||||||
@ -96,6 +96,7 @@ from babase import (
|
|||||||
timestring,
|
timestring,
|
||||||
UIScale,
|
UIScale,
|
||||||
unlock_all_input,
|
unlock_all_input,
|
||||||
|
utc_now_cloud,
|
||||||
WeakCall,
|
WeakCall,
|
||||||
workspaces_in_use,
|
workspaces_in_use,
|
||||||
)
|
)
|
||||||
@ -238,6 +239,7 @@ __all__ = [
|
|||||||
'UIScale',
|
'UIScale',
|
||||||
'UIV1AppSubsystem',
|
'UIV1AppSubsystem',
|
||||||
'unlock_all_input',
|
'unlock_all_input',
|
||||||
|
'utc_now_cloud',
|
||||||
'WeakCall',
|
'WeakCall',
|
||||||
'widget',
|
'widget',
|
||||||
'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
|
if uiscale is bui.UIScale.SMALL
|
||||||
else 530 if uiscale is bui.UIScale.MEDIUM else 600
|
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
|
yoffs = -45 if uiscale is bui.UIScale.SMALL else 0
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
@ -71,7 +71,7 @@ class InventoryWindow(bui.MainWindow):
|
|||||||
else:
|
else:
|
||||||
btn = bui.buttonwidget(
|
btn = bui.buttonwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
position=(x_offs + 50, height - 55 + yoffs),
|
position=(xoffs + 50, height - 55 + yoffs),
|
||||||
size=(60, 55),
|
size=(60, 55),
|
||||||
scale=0.8,
|
scale=0.8,
|
||||||
label=bui.charstr(bui.SpecialChar.BACK),
|
label=bui.charstr(bui.SpecialChar.BACK),
|
||||||
|
|||||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't modify them here.
|
// 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 char* kEngineVersion = "1.7.37";
|
||||||
const int kEngineApiVersion = 9;
|
const int kEngineApiVersion = 9;
|
||||||
|
|
||||||
|
|||||||
@ -2607,6 +2607,10 @@ static PyMethodDef PyGetSpecialWidgetDef = {
|
|||||||
" 'trophy_meter',"
|
" 'trophy_meter',"
|
||||||
" 'level_meter',"
|
" 'level_meter',"
|
||||||
" 'overlay_stack',"
|
" 'overlay_stack',"
|
||||||
|
" 'chest_0_button',"
|
||||||
|
" 'chest_1_button',"
|
||||||
|
" 'chest_2_button',"
|
||||||
|
" 'chest_3_button',"
|
||||||
" ]) -> bauiv1.Widget\n"
|
" ]) -> bauiv1.Widget\n"
|
||||||
"\n"
|
"\n"
|
||||||
"(internal)",
|
"(internal)",
|
||||||
|
|||||||
@ -1335,6 +1335,14 @@ auto RootWidget::GetSpecialWidget(const std::string& s) const -> Widget* {
|
|||||||
return level_meter_button_ ? level_meter_button_->widget.get() : nullptr;
|
return level_meter_button_ ? level_meter_button_->widget.get() : nullptr;
|
||||||
} else if (s == "overlay_stack") {
|
} else if (s == "overlay_stack") {
|
||||||
return overlay_stack_widget_;
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1462,7 +1470,7 @@ void RootWidget::SetChests(const std::string& chest_0_appearance,
|
|||||||
assert(b);
|
assert(b);
|
||||||
if (appearance == "") {
|
if (appearance == "") {
|
||||||
b->widget->set_color(0.473f, 0.44f, 0.583f);
|
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->width = b->height = 80.0f;
|
||||||
b->y = have_chests ? 44.0f : 0.0f;
|
b->y = have_chests ? 44.0f : 0.0f;
|
||||||
{
|
{
|
||||||
|
|||||||
@ -347,8 +347,6 @@ class BSClassicAccountLiveData:
|
|||||||
BSClassicChestAppearance,
|
BSClassicChestAppearance,
|
||||||
IOAttrs('a', enum_fallback=BSClassicChestAppearance.UNKNOWN),
|
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')]
|
unlock_time: Annotated[datetime.datetime, IOAttrs('t')]
|
||||||
ad_allow_time: Annotated[datetime.datetime | None, IOAttrs('at')]
|
ad_allow_time: Annotated[datetime.datetime | None, IOAttrs('at')]
|
||||||
|
|
||||||
@ -433,6 +431,85 @@ class BSInboxRequestResponse(Response):
|
|||||||
error: Annotated[str | None, IOAttrs('e')] = None
|
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):
|
class BSInboxEntryProcessType(Enum):
|
||||||
"""Types of processing we can ask for."""
|
"""Types of processing we can ask for."""
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user