mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-30 03:03:30 +08:00
Initial work on AppExperiences
This commit is contained in:
parent
7b8a98bf98
commit
183c5abf60
56
.efrocachemap
generated
56
.efrocachemap
generated
@ -4064,26 +4064,26 @@
|
||||
"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": "95166586256dc94f679d3f15cf570ed8",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "820f8a69f86434ff6dab9cc23e675708",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "70903ec2f476fbc5908cc52522f69e0c",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "442f2bdde3c176d9a4431c9fdcca892e",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "5354821ede7348ba9bb90bee8fe5ccb7",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "ab0cb59c874beb50e554d3d7c552565e",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "dec2c09bd136aa413b9b94729f7d6d2e",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "a5c43eb8befc810d693ec9c9f83fcba4",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "56bf9b14517f0a579964b39218498fcf",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "d6a10e3a6bc1a07609598f962439c6c8",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "ab5cb01ed4a8a8db80ca65ab5cd0133b",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "231bd6e18145b06028e4f90fd7de106c",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "3cc88ed5471e9b7f2b84af4ee58a8061",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "4586629e8f114c1b5a22444ae26b5917",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "e1177b377c3e48d60057a9719bf9d0e3",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "518c529a7133d5ea41d730d12ae156c4",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "41e7afae9395843c575c65593aab423c",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "d95e4cc445b722f111e51b3d4b7bdde9",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "d75e3afcc1db962cd483f8b80a65c930",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "2b1b27fc2ca79803d79796a7414db3a2",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "ca001c9f2b4edf8d4918c1bcaf0cb561",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "fcb58aae4535a761be49420f4e4a7711",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "8f453b8193ba06a3cc59374cdd2a1c09",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "7c389cb83619516ce96118227668500e",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "2ffcc486e9ba8f0fd5279083a2e54aff",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "366bab5bff3ff9344e54bf7492f4d7c3",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "78277cc1bd40ba88fd1475f8755e0721",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "5f063e4d45e40ade22f1bad63658752e",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "f7114c78146f22e89143218c9930b43e",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "90c0ea0ce7a35d8f15b2a29bef704819",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "e1b4932fd7f359404c979604a1e33444",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "28ab454f71dfecd1986a245eb4a732e7",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "7b1a4db9c3f36fd428cdafbc1459bc1b",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "bc5a48ff49975901f212d18b1dbbb6f5",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "7742db7c9555907fc7b2d5c89d48dfd0",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "d81bc55d666f630a14de90f30be29fb4",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "5ab68bfee69a6fe07b5b8a68938220e6",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "59a2b3cb2c1dde98c6aedf72aa9fdbfb",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "2199e800eb102d56197e11782b7adf12",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "3193300cf9927276893960698d8246f6",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "a3607fd941915ab11503f82acfc392b5",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "b5a129d83796c9e7015ab5e319d2c22f",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "a3607fd941915ab11503f82acfc392b5",
|
||||
@ -4100,14 +4100,14 @@
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "c5c40967e63471c9c4abd6dfbef892df",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "d34c0a142e7d391a109a33ea3cc77c08",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "c5c40967e63471c9c4abd6dfbef892df",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "aa15bc38411a8a4194b3711c9c6ebf56",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "3539534ba129d95e99f89ddf79d14f28",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "75e16f083a18621fe4502bc170e6a696",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "29b9a8543b1612c0451eaaf90647b905",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "4fb61373afaa6ce350601b245fcb1b7a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "d8e606cdfef72b6170721d87ee1d9b11",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "240b54fa0d4334591c0876a2b72a4663",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a7887447024ce5570da3f468bad5bbb4",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "13a3bb41dda8cfdb3ffdbc57a0390275",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "042ff1129bab0def6bf90250b5c08a32",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "699ab8e6fd3e8517acac76cd5b40dfbc",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "5b53317f8900cab59288be44b353dffc",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "978ea0ba60c026efd45729cd48c0feba",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "1fb524f11277090440cda18bfc3ee3a0",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "91452d47e879acd0d7fdd06a44fbcfed",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "7e9469f3cac9ab85c5e9d1256679604c",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "ad347097a38e0d7ede9eb6dec6a80ee9",
|
||||
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
@ -1,19 +1,19 @@
|
||||
### 1.7.28 (build 21299, api 8, 2023-09-01)
|
||||
### 1.7.28 (build 21303, api 8, 2023-09-01)
|
||||
|
||||
- Added some high level functionality for copying and deleting feature-sets to
|
||||
the `tools/spinoff` tool. For example, to create your own `poo` feature-set,
|
||||
do `tools/spinoff fset-copy template_fs poo`. Then do `make update` and `make
|
||||
cmake` to build and run the app, and from within it you should be able to do
|
||||
`import bapoo` to get at your nice shiny poo feature-set. When you are done
|
||||
playing, you can do `tools/spinoff fset-delete poo` to blow away any traces of
|
||||
it.
|
||||
the `spinoff` tool. For example, to create your own `poo` feature-set based on
|
||||
the existing `template_fs` one, do `tools/spinoff fset-copy template_fs poo`.
|
||||
Then do `make update` and `make cmake` to build and run the app, and from
|
||||
within it you should be able to do `import bapoo` to get at your nice shiny
|
||||
poo feature-set. When you are done playing around, you can do `tools/spinoff
|
||||
fset-delete poo` to blow away any traces of it.
|
||||
- Public builds now properly reconstruct the CMakeLists.txt file for project
|
||||
changes.
|
||||
- Efrocache now supports a starter-archive when building server builds. This
|
||||
means that if you do something like `make clean; make
|
||||
prefab-server-release-build` you should only see a few file downloads
|
||||
happening instead of hundreds or thousands which would happen before, which
|
||||
should be significantly faster & more efficient.
|
||||
prefab-server-release-build` you should see just a few file downloads
|
||||
happening instead of the hundreds that would happen before, which should be
|
||||
significantly faster & more efficient.
|
||||
|
||||
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
||||
|
||||
@ -40,7 +40,8 @@
|
||||
`build_number`, `device_name`, `config_file_path`, `version`, `debug_build`,
|
||||
`test_build`, `data_directory`, `python_directory_user`,
|
||||
`python_directory_app`, `python_directory_app_site`, `api_version`, `on_tv`,
|
||||
`vr_mode`.
|
||||
`vr_mode`, `toolbar_test`, `arcade_mode`, `headless_mode`, `demo_mode`, and
|
||||
`protocol_version`.
|
||||
- Reverting the Android keyboard changes from 1.7.26, as I've received a few
|
||||
reports of bluetooth game controllers now thinking they are keyboards. I'm
|
||||
thinking I'll have to bite the bullet and implement something that asks the
|
||||
|
||||
@ -96,6 +96,7 @@
|
||||
"ba_data/python/baclassic/osmusic.py",
|
||||
"ba_data/python/bacommon/__init__.py",
|
||||
"ba_data/python/bacommon/__pycache__/__init__.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/app.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/assets.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/bacloud.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/build.cpython-311.opt-1.pyc",
|
||||
@ -104,6 +105,7 @@
|
||||
"ba_data/python/bacommon/__pycache__/net.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/servermanager.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/transfer.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/bacommon/app.py",
|
||||
"ba_data/python/bacommon/assets.py",
|
||||
"ba_data/python/bacommon/bacloud.py",
|
||||
"ba_data/python/bacommon/build.py",
|
||||
|
||||
@ -712,6 +712,7 @@ $(eval $(call make-opt-pyc-target,$(element))))
|
||||
|
||||
SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/app.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/assets.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/bacloud.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/build.py \
|
||||
@ -746,6 +747,7 @@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
|
||||
|
||||
SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/app.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/assets.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/bacloud.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/build.cpython-311.opt-1.pyc \
|
||||
|
||||
@ -64,7 +64,7 @@ class AccountV2Subsystem:
|
||||
|
||||
def set_primary_credentials(self, credentials: str | None) -> None:
|
||||
"""Set credentials for the primary app account."""
|
||||
raise RuntimeError('This should be overridden.')
|
||||
raise NotImplementedError('This should be overridden.')
|
||||
|
||||
def have_primary_credentials(self) -> bool:
|
||||
"""Are credentials currently set for the primary app account?
|
||||
@ -73,7 +73,7 @@ class AccountV2Subsystem:
|
||||
only that they exist. If/when credentials are validated, the 'primary'
|
||||
account handle will be set.
|
||||
"""
|
||||
raise RuntimeError('This should be overridden.')
|
||||
raise NotImplementedError('This should be overridden.')
|
||||
|
||||
@property
|
||||
def primary(self) -> AccountV2Handle | None:
|
||||
|
||||
@ -112,7 +112,9 @@ class App:
|
||||
project.
|
||||
"""
|
||||
|
||||
def app_mode_for_intent(self, intent: AppIntent) -> type[AppMode]:
|
||||
def app_mode_for_intent(
|
||||
self, intent: AppIntent
|
||||
) -> type[AppMode] | None:
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
# __GOOD_PLACE_FOR_CUSTOM_SPINOFF_LOGIC__
|
||||
@ -127,10 +129,10 @@ class App:
|
||||
|
||||
import babase
|
||||
|
||||
if bascenev1.SceneV1AppMode.supports_intent(intent):
|
||||
if bascenev1.SceneV1AppMode.can_handle_intent(intent):
|
||||
return bascenev1.SceneV1AppMode
|
||||
|
||||
if babase.EmptyAppMode.supports_intent(intent):
|
||||
if babase.EmptyAppMode.can_handle_intent(intent):
|
||||
return babase.EmptyAppMode
|
||||
|
||||
raise RuntimeError(f'No handler found for intent {type(intent)}.')
|
||||
@ -144,19 +146,13 @@ class App:
|
||||
the single shared instance.
|
||||
"""
|
||||
|
||||
# Hack for docs-generation.
|
||||
if os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') == '1':
|
||||
return
|
||||
|
||||
self.env: babase.Env = _babase.Env()
|
||||
|
||||
self.state = self.State.NOT_RUNNING
|
||||
|
||||
# Controls which app-modes we use for handling given
|
||||
# app-intents. Plugins can override this to change high level
|
||||
# app behavior and spinoff projects can change the default
|
||||
# implementation for the same effect.
|
||||
self.mode_selector: babase.AppModeSelector | None = None
|
||||
|
||||
# Default executor which can be used for misc background
|
||||
# processing. It should also be passed to any additional asyncio
|
||||
# loops we create so that everything shares the same single set
|
||||
@ -193,6 +189,7 @@ class App:
|
||||
self._pending_intent: AppIntent | None = None
|
||||
self._intent: AppIntent | None = None
|
||||
self._mode: AppMode | None = None
|
||||
self._mode_selector: babase.AppModeSelector | None = None
|
||||
self._shutdown_task: asyncio.Task[None] | None = None
|
||||
self._shutdown_tasks: list[Coroutine[None, None, None]] = [
|
||||
self._wait_for_shutdown_suppressions()
|
||||
@ -201,6 +198,7 @@ class App:
|
||||
def postinit(self) -> None:
|
||||
"""Called after we've been inited and assigned to babase.app."""
|
||||
|
||||
# Hack for docs-generation.
|
||||
if os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') == '1':
|
||||
return
|
||||
|
||||
@ -231,6 +229,31 @@ class App:
|
||||
assert self._config is not None
|
||||
return self._config
|
||||
|
||||
@property
|
||||
def mode_selector(self) -> babase.AppModeSelector:
|
||||
"""Controls which app-modes are used for handling given intents.
|
||||
|
||||
Plugins can override this to change high level app behavior and
|
||||
spinoff projects can change the default implementation for the
|
||||
same effect.
|
||||
"""
|
||||
if self._mode_selector is None:
|
||||
raise RuntimeError(
|
||||
'mode_selector cannot be used until the app reaches'
|
||||
' the running state.'
|
||||
)
|
||||
return self._mode_selector
|
||||
|
||||
@mode_selector.setter
|
||||
def mode_selector(self, selector: babase.AppModeSelector) -> None:
|
||||
# Don't allow overriding this until after we've initially set it.
|
||||
if self._mode_selector is None:
|
||||
raise RuntimeError(
|
||||
'mode_selector cannot be used until the app reaches'
|
||||
' the running state.'
|
||||
)
|
||||
self._mode_selector = selector
|
||||
|
||||
# __FEATURESET_APP_SUBSYSTEM_PROPERTIES_BEGIN__
|
||||
# This section generated by batools.appmodule; do not edit.
|
||||
|
||||
@ -303,8 +326,8 @@ class App:
|
||||
def run(self) -> None:
|
||||
"""Run the app to completion.
|
||||
|
||||
Note that this only works on platforms where Ballistica
|
||||
manages its own event loop.
|
||||
Note that this only works on builds where Ballistica manages
|
||||
its own event loop.
|
||||
"""
|
||||
_babase.run_app()
|
||||
|
||||
@ -423,7 +446,7 @@ class App:
|
||||
self._update_state()
|
||||
|
||||
def _set_intent(self, intent: AppIntent) -> None:
|
||||
# This should be running in a bg thread.
|
||||
# This should be happening in a bg thread.
|
||||
assert not _babase.in_logic_thread()
|
||||
try:
|
||||
# Ask the selector what app-mode to use for this intent.
|
||||
@ -431,15 +454,27 @@ class App:
|
||||
raise RuntimeError('No AppModeSelector set.')
|
||||
modetype = self.mode_selector.app_mode_for_intent(intent)
|
||||
|
||||
# Make sure the app-mode they return *actually* supports the
|
||||
# intent.
|
||||
if not modetype.supports_intent(intent):
|
||||
# NOTE: Since intents are somewhat high level things, should
|
||||
# we do some universal thing like a screenmessage saying
|
||||
# 'The app cannot handle that request' on failure?
|
||||
|
||||
if modetype is None:
|
||||
raise RuntimeError(
|
||||
f'Intent {intent} is not supported by AppMode class'
|
||||
f' {modetype}'
|
||||
f'No app-mode found to handle app-intent'
|
||||
f' type {type(intent)}.'
|
||||
)
|
||||
|
||||
# Kick back to the logic thread to apply.
|
||||
# Make sure the app-mode the selector gave us *actually*
|
||||
# supports the intent.
|
||||
if not modetype.can_handle_intent(intent):
|
||||
raise RuntimeError(
|
||||
f'Intent {intent} cannot be handled by AppMode type'
|
||||
f' {modetype} (selector {self.mode_selector}'
|
||||
f' incorrectly thinks that it can be).'
|
||||
)
|
||||
|
||||
# Ok; seems legit. Now instantiate the mode if necessary and
|
||||
# kick back to the logic thread to apply.
|
||||
mode = modetype()
|
||||
_babase.pushcall(
|
||||
tpartial(self._apply_intent, intent, mode),
|
||||
@ -480,6 +515,9 @@ class App:
|
||||
# Hmm; what should we do in this case?...
|
||||
logging.exception('Error activating app-mode %s.', mode)
|
||||
|
||||
# Let the world know when we first have an app-mode; certain
|
||||
# app stuff such as input processing can proceed at that
|
||||
# point.
|
||||
if is_initial_mode:
|
||||
_babase.on_initial_app_mode_set()
|
||||
|
||||
@ -599,7 +637,7 @@ class App:
|
||||
|
||||
# Set a default app-mode-selector. Plugins can then override
|
||||
# this if they want in the on_app_running callback below.
|
||||
self.mode_selector = self.DefaultAppModeSelector()
|
||||
self._mode_selector = self.DefaultAppModeSelector()
|
||||
|
||||
# Inform all app subsystems in the same order they were
|
||||
# registered. Operate on a copy here because subsystems can
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"""Provides the AppConfig class."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _babase
|
||||
@ -120,33 +121,24 @@ def read_app_config() -> tuple[AppConfig, bool]:
|
||||
config = AppConfig()
|
||||
config_file_healthy = True
|
||||
|
||||
except Exception as exc:
|
||||
print(
|
||||
(
|
||||
'error reading config file at time '
|
||||
+ str(_babase.apptime())
|
||||
+ ': \''
|
||||
+ config_file_path
|
||||
+ '\':\n'
|
||||
),
|
||||
exc,
|
||||
except Exception:
|
||||
logging.exception(
|
||||
"Error reading config file at time %.3f: '%s'.",
|
||||
_babase.apptime(),
|
||||
config_file_path,
|
||||
)
|
||||
|
||||
# Whenever this happens lets back up the broken one just in case it
|
||||
# gets overwritten accidentally.
|
||||
print(
|
||||
(
|
||||
'backing up current config file to \''
|
||||
+ config_file_path
|
||||
+ ".broken\'"
|
||||
)
|
||||
logging.info(
|
||||
"Backing up current config file to '%s.broken'", config_file_path
|
||||
)
|
||||
try:
|
||||
import shutil
|
||||
|
||||
shutil.copyfile(config_file_path, config_file_path + '.broken')
|
||||
except Exception as exc2:
|
||||
print('EXC copying broken config:', exc2)
|
||||
except Exception:
|
||||
logging.exception('Error copying broken config.')
|
||||
config = AppConfig()
|
||||
|
||||
# Now attempt to read one of our 'prev' backup copies.
|
||||
@ -159,9 +151,9 @@ def read_app_config() -> tuple[AppConfig, bool]:
|
||||
else:
|
||||
config = AppConfig()
|
||||
config_file_healthy = True
|
||||
print('successfully read backup config.')
|
||||
except Exception as exc2:
|
||||
print('EXC reading prev backup config:', exc2)
|
||||
logging.info('Successfully read backup config.')
|
||||
except Exception:
|
||||
logging.exception('Error reading prev backup config.')
|
||||
return config, config_file_healthy
|
||||
|
||||
|
||||
@ -176,7 +168,7 @@ def commit_app_config(force: bool = False) -> None:
|
||||
assert plus is not None
|
||||
|
||||
if not _babase.app.config_file_healthy and not force:
|
||||
print(
|
||||
logging.warning(
|
||||
'Current config file is broken; '
|
||||
'skipping write to avoid losing settings.'
|
||||
)
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bacommon.app import AppExperience
|
||||
from babase._appintent import AppIntent
|
||||
|
||||
|
||||
@ -17,16 +18,33 @@ class AppMode:
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def supports_intent(cls, intent: AppIntent) -> bool:
|
||||
"""Return whether our mode can handle the provided intent."""
|
||||
del intent
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
"""Return the overall experience provided by this mode."""
|
||||
raise NotImplementedError('AppMode subclasses must override this.')
|
||||
|
||||
# Say no to everything by default. Let's make mode explicitly
|
||||
# lay out everything they *do* support.
|
||||
return False
|
||||
@classmethod
|
||||
def can_handle_intent(cls, intent: AppIntent) -> bool:
|
||||
"""Return whether this mode can handle the provided intent.
|
||||
|
||||
For this to return True, the AppMode must claim to support the
|
||||
provided intent (via its _supports_intent() method) AND the
|
||||
AppExperience associated with the AppMode must be supported by
|
||||
the current app and runtime environment.
|
||||
"""
|
||||
return cls._supports_intent(intent)
|
||||
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
"""Return whether our mode can handle the provided intent.
|
||||
|
||||
AppModes should override this to define what they can handle.
|
||||
Note that AppExperience does not have to be considered here; that
|
||||
is handled automatically by the can_handle_intent() call."""
|
||||
raise NotImplementedError('AppMode subclasses must override this.')
|
||||
|
||||
def handle_intent(self, intent: AppIntent) -> None:
|
||||
"""Handle an intent."""
|
||||
raise NotImplementedError('AppMode subclasses must override this.')
|
||||
|
||||
def on_activate(self) -> None:
|
||||
"""Called when the mode is being activated."""
|
||||
|
||||
@ -18,15 +18,15 @@ class AppModeSelector:
|
||||
The app calls an instance of this class when passed an AppIntent to
|
||||
determine which AppMode to use to handle the intent. Plugins or
|
||||
spinoff projects can modify high level app behavior by replacing or
|
||||
modifying this.
|
||||
modifying the app's mode-selector.
|
||||
"""
|
||||
|
||||
def app_mode_for_intent(self, intent: AppIntent) -> type[AppMode]:
|
||||
def app_mode_for_intent(self, intent: AppIntent) -> type[AppMode] | None:
|
||||
"""Given an AppIntent, return the AppMode that should handle it.
|
||||
|
||||
If None is returned, the AppIntent will be ignored.
|
||||
|
||||
This is called in a background thread, so avoid any calls
|
||||
This may be called in a background thread, so avoid any calls
|
||||
limited to logic thread use/etc.
|
||||
"""
|
||||
raise RuntimeError('app_mode_for_intent() should be overridden.')
|
||||
raise NotImplementedError('app_mode_for_intent() should be overridden.')
|
||||
|
||||
@ -5,6 +5,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bacommon.app import AppExperience
|
||||
|
||||
import _babase
|
||||
from babase._appmode import AppMode
|
||||
from babase._appintent import AppIntentExec, AppIntentDefault
|
||||
@ -17,7 +19,11 @@ class EmptyAppMode(AppMode):
|
||||
"""An empty app mode that can be used as a fallback/etc."""
|
||||
|
||||
@classmethod
|
||||
def supports_intent(cls, intent: AppIntent) -> bool:
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.EMPTY
|
||||
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
@ -30,8 +36,8 @@ class EmptyAppMode(AppMode):
|
||||
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.empty_app_mode_activate()
|
||||
_babase.on_empty_app_mode_activate()
|
||||
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.empty_app_mode_deactivate()
|
||||
_babase.on_empty_app_mode_deactivate()
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21299
|
||||
TARGET_BALLISTICA_BUILD = 21303
|
||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,9 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bacommon.app import AppExperience
|
||||
from babase import AppMode, AppIntentExec, AppIntentDefault
|
||||
|
||||
import _bascenev1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -16,7 +18,11 @@ class SceneV1AppMode(AppMode):
|
||||
"""Our app-mode."""
|
||||
|
||||
@classmethod
|
||||
def supports_intent(cls, intent: AppIntent) -> bool:
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.MELEE
|
||||
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
@ -29,8 +35,8 @@ class SceneV1AppMode(AppMode):
|
||||
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.app_mode_activate()
|
||||
_bascenev1.on_app_mode_activate()
|
||||
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.app_mode_deactivate()
|
||||
_bascenev1.on_app_mode_deactivate()
|
||||
|
||||
@ -371,5 +371,5 @@ def register_map(maptype: type[Map]) -> None:
|
||||
"""Register a map class with the game."""
|
||||
assert babase.app.classic is not None
|
||||
if maptype.name in babase.app.classic.maps:
|
||||
raise RuntimeError('map "' + maptype.name + '" already registered')
|
||||
raise RuntimeError(f'Map "{maptype.name}" is already registered.')
|
||||
babase.app.classic.maps[maptype.name] = maptype
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Snippets of code for use by the c++ layer."""
|
||||
|
||||
# (most of these are self-explanatory)
|
||||
# pylint: disable=missing-function-docstring
|
||||
"""Snippets of code for use by the native layer."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def hello_world() -> None:
|
||||
"""The usual example."""
|
||||
print('HELLO WORLD FROM TemplateFs!')
|
||||
|
||||
@ -991,12 +991,13 @@ void Graphics::ClearFrameDefDeleteList() {
|
||||
}
|
||||
|
||||
void Graphics::FadeScreen(bool to, millisecs_t time, PyObject* endcall) {
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
// If there's an ourstanding fade-end command, go ahead and run it.
|
||||
// (otherwise, overlapping fades can cause things to get lost)
|
||||
if (fade_end_call_.Exists()) {
|
||||
if (g_buildconfig.debug_build()) {
|
||||
Log(LogLevel::kWarning,
|
||||
"2 fades overlapping; running first fade-end-call early");
|
||||
"2 fades overlapping; running first fade-end-call early.");
|
||||
}
|
||||
fade_end_call_->Schedule();
|
||||
fade_end_call_.Clear();
|
||||
@ -1089,7 +1090,7 @@ void Graphics::ApplyCamera(FrameDef* frame_def) {
|
||||
void Graphics::DrawWorld(FrameDef* frame_def) {
|
||||
assert(!g_core->HeadlessMode());
|
||||
|
||||
// Draw all session contents (nodes, etc.)
|
||||
// Draw the world.
|
||||
overlay_node_z_depth_ = -0.95f;
|
||||
g_base->app_mode()->DrawWorld(frame_def);
|
||||
g_base->bg_dynamics->Draw(frame_def);
|
||||
@ -1120,9 +1121,6 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
// layer is fully bootstrapped.
|
||||
BA_PRECONDITION_FATAL(g_base->logic->app_bootstrapping_complete());
|
||||
|
||||
// This should no longer be necessary..
|
||||
WaitForRendererToExist();
|
||||
|
||||
millisecs_t app_time_millisecs = g_core->GetAppTimeMillisecs();
|
||||
|
||||
// Store how much time this frame_def represents.
|
||||
@ -1132,8 +1130,9 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
millisecs_t{50}, display_time_millisecs - last_create_frame_def_time_);
|
||||
last_create_frame_def_time_ = display_time_millisecs;
|
||||
|
||||
// This probably should not be here. Though I guess we get the most up-to-date
|
||||
// values possible this way. But it should probably live in g_input.
|
||||
// This probably should not be here. Though I guess we get the most
|
||||
// up-to-date values possible this way. But it should probably live in
|
||||
// g_input.
|
||||
UpdateGyro(app_time_millisecs, elapsed);
|
||||
|
||||
FrameDef* frame_def = GetEmptyFrameDef();
|
||||
@ -1184,9 +1183,9 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
// Draw our light/shadow images to the screen if desired.
|
||||
DrawDebugBuffers(overlay_pass);
|
||||
|
||||
// In high-quality modes we draw a screen-quad as a catch-all for blitting
|
||||
// the world buffer to the screen (other nodes can add their own blitters
|
||||
// such as distortion shapes which will have priority).
|
||||
// In high-quality modes we draw a screen-quad as a catch-all for
|
||||
// blitting the world buffer to the screen (other nodes can add their
|
||||
// own blitters such as distortion shapes which will have priority).
|
||||
if (frame_def->quality() >= GraphicsQuality::kHigh) {
|
||||
PostProcessComponent c(frame_def->blit_pass());
|
||||
c.DrawScreenQuad();
|
||||
@ -1195,8 +1194,8 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
|
||||
DrawFades(frame_def, app_time_millisecs);
|
||||
|
||||
// Sanity test: If we're in VR, the only reason we should have stuff in the
|
||||
// flat overlay pass is if there's windows present (we want to avoid
|
||||
// Sanity test: If we're in VR, the only reason we should have stuff in
|
||||
// the flat overlay pass is if there's windows present (we want to avoid
|
||||
// drawing/blitting the 2d UI buffer during gameplay for efficiency).
|
||||
if (g_core->IsVRMode()) {
|
||||
if (frame_def->GetOverlayFlatPass()->HasDrawCommands()) {
|
||||
@ -1219,9 +1218,9 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
|
||||
frame_def->Finalize();
|
||||
|
||||
// Include all mesh-data loads and unloads that have accumulated up to this
|
||||
// point the graphics thread will have to handle these before rendering the
|
||||
// frame_def.
|
||||
// Include all mesh-data loads and unloads that have accumulated up to
|
||||
// this point the graphics thread will have to handle these before
|
||||
// rendering the frame_def.
|
||||
frame_def->set_mesh_data_creates(mesh_data_creates_);
|
||||
mesh_data_creates_.clear();
|
||||
frame_def->set_mesh_data_destroys(mesh_data_destroys_);
|
||||
@ -1327,7 +1326,7 @@ void Graphics::UpdateAndDrawProgressBar(FrameDef* frame_def,
|
||||
/ static_cast<float>(progress_bar_loads_));
|
||||
DrawProgressBar(pass, 1.0f);
|
||||
|
||||
// If we were drawing a progress bar, see if everything is now loaded.. if
|
||||
// If we were drawing a progress bar, see if everything is now loaded. If
|
||||
// so, start rendering normally next frame.
|
||||
int count = g_base->assets->GetGraphicalPendingLoadCount();
|
||||
if (count <= 0) {
|
||||
@ -1570,8 +1569,8 @@ void Graphics::AddMeshDataCreate(MeshData* d) {
|
||||
assert(g_base->graphics);
|
||||
|
||||
// Add this to our list of new-mesh-datas. We'll include this with our
|
||||
// next frame_def to have the graphics thread load before it processes
|
||||
// the frame_def.
|
||||
// next frame_def to have the graphics thread load before it processes the
|
||||
// frame_def.
|
||||
mesh_data_creates_.push_back(d);
|
||||
}
|
||||
|
||||
@ -1580,8 +1579,8 @@ void Graphics::AddMeshDataDestroy(MeshData* d) {
|
||||
assert(g_base->graphics);
|
||||
|
||||
// Add this to our list of delete-mesh-datas; we'll include this with our
|
||||
// next frame_def to have the graphics thread kill before it processes
|
||||
// the frame_def.
|
||||
// next frame_def to have the graphics thread kill before it processes the
|
||||
// frame_def.
|
||||
mesh_data_destroys_.push_back(d);
|
||||
}
|
||||
|
||||
@ -1635,24 +1634,6 @@ void Graphics::ToggleDebugDraw() {
|
||||
|
||||
void Graphics::ReleaseFadeEndCommand() { fade_end_call_.Clear(); }
|
||||
|
||||
void Graphics::WaitForRendererToExist() {
|
||||
// Conceivably we could hit this point before our graphics thread has created
|
||||
// the renderer. In that case lets wait a moment.
|
||||
int sleep_count = 0;
|
||||
while (g_base->graphics_server == nullptr
|
||||
|| g_base->graphics_server->renderer() == nullptr) {
|
||||
BA_LOG_ONCE(
|
||||
LogLevel::kWarning,
|
||||
"BuildAndPushFrameDef() called before renderer is up; spinning...");
|
||||
core::CorePlatform::SleepMillisecs(100);
|
||||
sleep_count++;
|
||||
if (sleep_count > 100) {
|
||||
throw Exception(
|
||||
"Aborting waiting for renderer to come up in BuildAndPushFrameDef()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Graphics::ValueTest(const std::string& arg, double* absval,
|
||||
double* deltaval, double* outval) -> bool {
|
||||
return false;
|
||||
@ -1737,20 +1718,17 @@ void Graphics::DoDrawBlotch(std::vector<uint16_t>* indices,
|
||||
}
|
||||
|
||||
void Graphics::DrawRadialMeter(MeshIndexedSimpleFull* m, float amt) {
|
||||
// FIXME - we're updating this every frame so we should use pure dynamic data;
|
||||
// not a mix of static and dynamic.
|
||||
// FIXME - we're updating this every frame so we should use pure dynamic
|
||||
// data; not a mix of static and dynamic.
|
||||
|
||||
if (amt >= 0.999f) {
|
||||
// clang-format off
|
||||
uint16_t indices[] = {0, 1, 2, 1, 3, 2};
|
||||
VertexSimpleFull vertices[] = {
|
||||
{-1, -1, 0, 0, 65535},
|
||||
{1, -1, 0, 65535, 65535},
|
||||
{-1, 1, 0, 0, 0},
|
||||
{1, 1, 0, 65535, 0,
|
||||
}
|
||||
{1, 1, 0, 65535, 0},
|
||||
};
|
||||
// clang-format on
|
||||
m->SetIndexData(Object::New<MeshIndexBuffer16>(6, indices));
|
||||
m->SetData(Object::New<MeshBuffer<VertexSimpleFull>>(4, vertices));
|
||||
|
||||
|
||||
@ -322,7 +322,6 @@ class Graphics {
|
||||
void DrawCursor(RenderPass* pass, millisecs_t real_time);
|
||||
void DrawFades(FrameDef* frame_def, millisecs_t real_time);
|
||||
void DrawDebugBuffers(RenderPass* pass);
|
||||
void WaitForRendererToExist();
|
||||
|
||||
void UpdateAndDrawProgressBar(FrameDef* frame_def, millisecs_t real_time);
|
||||
void DoDrawBlotch(std::vector<uint16_t>* indices,
|
||||
@ -344,7 +343,7 @@ class Graphics {
|
||||
std::vector<MeshData*> mesh_data_creates_;
|
||||
std::vector<MeshData*> mesh_data_destroys_;
|
||||
bool has_supports_high_quality_graphics_value_{};
|
||||
bool supports_high_quality_graphics_ = false;
|
||||
bool supports_high_quality_graphics_{};
|
||||
millisecs_t last_create_frame_def_time_{};
|
||||
Vector3f shadow_offset_{0.0f, 0.0f, 0.0f};
|
||||
Vector2f shadow_scale_{1.0f, 1.0f};
|
||||
|
||||
@ -1370,9 +1370,9 @@ static PyMethodDef PyUserAgentStringDef = {
|
||||
"(internal)\n",
|
||||
};
|
||||
|
||||
// ----------------------- empty_app_mode_activate -----------------------------
|
||||
// --------------------- on_empty_app_mode_activate ----------------------------
|
||||
|
||||
static auto PyEmptyAppModeActivate(PyObject* self) -> PyObject* {
|
||||
static auto PyOnEmptyAppModeActivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
g_base->set_app_mode(AppModeEmpty::GetSingleton());
|
||||
@ -1382,19 +1382,19 @@ static auto PyEmptyAppModeActivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
static PyMethodDef PyEmptyAppModeActivateDef = {
|
||||
"empty_app_mode_activate", // name
|
||||
(PyCFunction)PyEmptyAppModeActivate, // method
|
||||
METH_NOARGS, // flags
|
||||
static PyMethodDef PyOnEmptyAppModeActivateDef = {
|
||||
"on_empty_app_mode_activate", // name
|
||||
(PyCFunction)PyOnEmptyAppModeActivate, // method
|
||||
METH_NOARGS, // flags
|
||||
|
||||
"empty_app_mode_activate() -> None\n"
|
||||
"on_empty_app_mode_activate() -> None\n"
|
||||
"\n"
|
||||
"(internal)\n",
|
||||
};
|
||||
|
||||
// ----------------------- empty_app_mode_deactivate ---------------------------
|
||||
// --------------------- on_empty_app_mode_deactivate --------------------------
|
||||
|
||||
static auto PyEmptyAppModeDeactivate(PyObject* self) -> PyObject* {
|
||||
static auto PyOnEmptyAppModeDeactivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
// Currently doing nothing.
|
||||
@ -1402,12 +1402,12 @@ static auto PyEmptyAppModeDeactivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
static PyMethodDef PyEmptyAppModeDeactivateDef = {
|
||||
"empty_app_mode_deactivate", // name
|
||||
(PyCFunction)PyEmptyAppModeDeactivate, // method
|
||||
METH_NOARGS, // flags
|
||||
static PyMethodDef PyOnEmptyAppModeDeactivateDef = {
|
||||
"on_empty_app_mode_deactivate", // name
|
||||
(PyCFunction)PyOnEmptyAppModeDeactivate, // method
|
||||
METH_NOARGS, // flags
|
||||
|
||||
"empty_app_mode_deactivate() -> None\n"
|
||||
"on_empty_app_mode_deactivate() -> None\n"
|
||||
"\n"
|
||||
"(internal)\n",
|
||||
};
|
||||
@ -1598,8 +1598,8 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
||||
PyOnInitialAppModeSetDef,
|
||||
PyReachedEndOfBaBaseDef,
|
||||
PyUserAgentStringDef,
|
||||
PyEmptyAppModeActivateDef,
|
||||
PyEmptyAppModeDeactivateDef,
|
||||
PyOnEmptyAppModeActivateDef,
|
||||
PyOnEmptyAppModeDeactivateDef,
|
||||
PyEmptyAppModeHandleIntentDefaultDef,
|
||||
PyEmptyAppModeHandleIntentExecDef,
|
||||
PyGetImmediateReturnCodeDef,
|
||||
|
||||
@ -525,8 +525,7 @@ static auto PyFadeScreen(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
-> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
|
||||
// This can only be called in the UI context.
|
||||
int fade{0};
|
||||
int fade{};
|
||||
float time{0.25f};
|
||||
PyObject* endcall = nullptr;
|
||||
static const char* kwlist[] = {"to", "time", "endcall", nullptr};
|
||||
|
||||
@ -1614,9 +1614,9 @@ static PyMethodDef PySetInternalMusicDef = {
|
||||
"(internal).",
|
||||
};
|
||||
|
||||
// --------------------------- app_mode_activate -------------------------------
|
||||
// -------------------------- on_app_mode_activate -----------------------------
|
||||
|
||||
static auto PyAppModeActivate(PyObject* self) -> PyObject* {
|
||||
static auto PyOnAppModeActivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
g_base->set_app_mode(SceneV1AppMode::GetSingleton());
|
||||
@ -1624,19 +1624,19 @@ static auto PyAppModeActivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
static PyMethodDef PyAppModeActivateDef = {
|
||||
"app_mode_activate", // name
|
||||
(PyCFunction)PyAppModeActivate, // method
|
||||
METH_NOARGS, // flags
|
||||
static PyMethodDef PyOnAppModeActivateDef = {
|
||||
"on_app_mode_activate", // name
|
||||
(PyCFunction)PyOnAppModeActivate, // method
|
||||
METH_NOARGS, // flags
|
||||
|
||||
"app_mode_activate() -> None\n"
|
||||
"on_app_mode_activate() -> None\n"
|
||||
"\n"
|
||||
"(internal)\n",
|
||||
};
|
||||
|
||||
// -------------------------- app_mode_deactivate ------------------------------
|
||||
// ------------------------- on_app_mode_deactivate ----------------------------
|
||||
|
||||
static auto PyAppModeDeactivate(PyObject* self) -> PyObject* {
|
||||
static auto PyOnAppModeDeactivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
// Currently doing nothing.
|
||||
@ -1644,12 +1644,12 @@ static auto PyAppModeDeactivate(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
static PyMethodDef PyAppModeDeactivateDef = {
|
||||
"app_mode_deactivate", // name
|
||||
(PyCFunction)PyAppModeDeactivate, // method
|
||||
METH_NOARGS, // flags
|
||||
static PyMethodDef PyOnAppModeDeactivateDef = {
|
||||
"on_app_mode_deactivate", // name
|
||||
(PyCFunction)PyOnAppModeDeactivate, // method
|
||||
METH_NOARGS, // flags
|
||||
|
||||
"app_mode_deactivate() -> None\n"
|
||||
"on_app_mode_deactivate() -> None\n"
|
||||
"\n"
|
||||
"(internal)\n",
|
||||
};
|
||||
@ -1771,8 +1771,8 @@ auto PythonMethodsScene::GetMethods() -> std::vector<PyMethodDef> {
|
||||
PyBaseTimeDef,
|
||||
PyBaseTimerDef,
|
||||
PyLsInputDevicesDef,
|
||||
PyAppModeActivateDef,
|
||||
PyAppModeDeactivateDef,
|
||||
PyOnAppModeActivateDef,
|
||||
PyOnAppModeDeactivateDef,
|
||||
PyHandleAppIntentDefaultDef,
|
||||
PyHandleAppIntentExecDef,
|
||||
PyProtocolVersionDef,
|
||||
|
||||
@ -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 = 21299;
|
||||
const int kEngineBuildNumber = 21303;
|
||||
const char* kEngineVersion = "1.7.28";
|
||||
const int kEngineApiVersion = 8;
|
||||
|
||||
|
||||
35
tools/bacommon/app.py
Normal file
35
tools/bacommon/app.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Common high level values/functionality related to apps."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class AppExperience(Enum):
|
||||
"""Overall experience that can be provided by a Ballistica app.
|
||||
|
||||
This corresponds generally, but not exactly, to distinct apps built
|
||||
with Ballistica. However, a single app may support multiple experiences,
|
||||
or there may be multiple apps targeting one experience. Cloud components
|
||||
such as leagues are generally associated with an AppExperience.
|
||||
"""
|
||||
|
||||
# A special experience category that is supported everywhere. Used
|
||||
# for the default empty AppMode when starting the app, etc.
|
||||
EMPTY = 'empty'
|
||||
|
||||
# The traditional BombSquad experience: multiple players using
|
||||
# controllers in a single arena small enough for all action to be
|
||||
# viewed on a single screen.
|
||||
MELEE = 'melee'
|
||||
|
||||
# The traditional BombSquad Remote experience; buttons on a
|
||||
# touch-screen allowing a mobile device to be used as a game
|
||||
# controller.
|
||||
REMOTE = 'remote'
|
||||
@ -166,12 +166,12 @@ def generate_app_module(
|
||||
|
||||
if 'scene_v1' in fsets:
|
||||
contents += (
|
||||
'if bascenev1.SceneV1AppMode.supports_intent(intent):\n'
|
||||
'if bascenev1.SceneV1AppMode.can_handle_intent(intent):\n'
|
||||
' return bascenev1.SceneV1AppMode\n\n'
|
||||
)
|
||||
if 'base' in fsets:
|
||||
contents += (
|
||||
'if babase.EmptyAppMode.supports_intent(intent):\n'
|
||||
'if babase.EmptyAppMode.can_handle_intent(intent):\n'
|
||||
' return babase.EmptyAppMode\n\n'
|
||||
)
|
||||
contents += (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user