babase package¶
Common shared Ballistica components.
For modding purposes, this package should generally not be used
directly. Instead one should use purpose-built packages such as
bascenev1
or bauiv1
which themselves import various
functionality from here and reexpose it in a more focused way.
- class babase.AccountV2Handle[source]¶
Bases:
object
Handle for interacting with a V2 account.
This class supports the
with
statement, which is how it is used with some operations such as cloud messaging.
- class babase.AccountV2Subsystem[source]¶
Bases:
object
Subsystem for modern account handling in the app.
Access the single shared instance of this class via the
accounts
attr on thePlusAppSubsystem
class.- have_primary_credentials() bool [source]¶
Are credentials currently set for the primary app account?
Note that this does not mean these credentials have been checked for validity; only that they exist. If/when credentials are validated, the
primary
account handle will be set.
- property primary: AccountV2Handle | None¶
The primary account for the app, or None if not logged in.
- exception babase.ActivityNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected activity does not exist.
- exception babase.ActorNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected actor does not exist.
- class babase.App[source]¶
Bases:
object
High level Ballistica app functionality and state.
Access the single shared instance of this class via the
app
attr available on various high level modules such asbabase
,bauiv1
, andbascenev1
.- SHUTDOWN_TASK_TIMEOUT_SECONDS = 12¶
How long we allow shutdown tasks to run before killing them. Currently the entire app hard-exits if shutdown takes 15 seconds, so we need to keep it under that. Staying above 10 should allow 10 second network timeouts to happen though.
- property active: bool¶
Whether the app is currently front and center.
This will be False when the app is hidden, other activities are covering it, etc. (depending on the platform).
- add_shutdown_task(coro: Coroutine[None, None, None]) None [source]¶
Add a task to be run on app shutdown.
Note that shutdown tasks will be canceled after
SHUTDOWN_TASK_TIMEOUT_SECONDS
if they are still running.
- property asyncio_loop: AbstractEventLoop¶
The logic thread’s
asyncio
event-loop.This allows
asyncio
tasks to be run in the logic thread.Generally you should call
create_async_task()
to schedule async code to run instead of using this directly. That will handle retaining the task and logging errors automatically. Only schedule tasks ontoasyncio_loop
yourself when you intend to hold on to the returned task and await its results. Releasing the task reference can lead to subtle bugs such as unreported errors and garbage-collected tasks disappearing before their work is done.Note that, at this time, the asyncio loop is encapsulated and explicitly stepped by the engine’s logic thread loop and thus things like
asyncio.get_running_loop()
will unintuitively not return this loop from most places in the logic thread; only from within a task explicitly created in this loop. Hopefully this situation will be improved in the future with a unified event loop.
- property classic: ClassicAppSubsystem | None¶
Our classic subsystem (if available).
- create_async_task(coro: Coroutine[Any, Any, T], *, name: str | None = None) None [source]¶
Create a fully managed
asyncio
task.This will automatically retain and release a reference to the task and log any exceptions that occur in it. If you need to await a task or otherwise need more control, schedule a task directly using
asyncio_loop
.
- devconsole: DevConsoleSubsystem¶
Subsystem for wrangling the dev-console UI.
- env: babase.Env¶
Static environment values for the app.
- fg_state: int¶
Incremented each time the app leaves the
SUSPENDED
state. This can be a simple way to determine if network data should be refreshed/etc.
- health: AppHealthSubsystem¶
Subsystem for keeping tabs on app health.
- lang: LanguageSubsystem¶
Language subsystem.
- meta: MetadataSubsystem¶
Subsystem for wrangling metadata.
- property mode_selector: 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.
- net: NetworkSubsystem¶
Subsystem for network functionality.
- plugins: PluginSubsystem¶
Subsystem for wrangling plugins.
- property plus: PlusAppSubsystem | None¶
Our plus subsystem (if available).
- postinit() None [source]¶
Called after we’ve been inited and assigned to
babase.app
.Anything that accesses
babase.app
as part of its init process must go here instead of __init__.
- run() None [source]¶
Run the app to completion.
Note that this only works on builds/runs where Ballistica is managing its own event loop.
- set_intent(intent: AppIntent) None [source]¶
Set the intent for the app.
Intent defines what the app is trying to do at a given time. This call is asynchronous; the intent switch will happen in the logic thread in the near future. If this is called repeatedly before the change takes place, the final intent to be set will be used.
- stringedit: StringEditSubsystem¶
Subsystem for wrangling text input from various sources.
- threadpool: ThreadPoolExecutorEx¶
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 of worker threads.
- property ui_v1: UIV1AppSubsystem¶
Our ui_v1 subsystem (always available).
- workspaces: WorkspaceSubsystem¶
Subsystem for wrangling workspaces.
- class babase.AppConfig[source]¶
Bases:
dict
A special dict that holds persistent app configuration values.
It also provides methods for fetching values with app-defined fallback defaults, applying contained values to the game, and committing the config to storage.
Access the single shared instance of this config via the
config
attr on theApp
class.App-config data is stored as json on disk on so make sure to only place json-friendly values in it (
dict
,list
,str
,float
,int
,bool
). Be aware that tuples will be quietly converted to lists when stored.- apply() None [source]¶
Apply config values to the running app.
This call is thread-safe and asynchronous; changes will happen in the next logic event loop cycle.
- apply_and_commit() None [source]¶
Shortcut to run
apply()
followed bycommit()
.This way the
commit()
will not occur ifapply()
hits invalid data, which is generally desirable.
- builtin_keys() list[str] [source]¶
Return the list of valid key names recognized by this class.
This set of keys can be used with
resolve()
,default_value()
, etc. It does not vary across platforms and may include keys that are obsolete or not relevant on the current running version. (for instance, VR related keys on non-VR platforms). This is to minimize the amount of platform checking necessary)Note that it is perfectly legal to store arbitrary named data in the config, but in that case it is up to the user to test for the existence of the key in the config dict, fall back to consistent defaults, etc.
- commit() None [source]¶
Commits the config to local storage.
Note that this call is asynchronous so the actual write to disk may not occur immediately.
- default_value(key: str) Any [source]¶
Given a string key, return its predefined default value.
This is the value that will be returned by
resolve()
if the key is not present in the config dict or of an incompatible type.Raises an Exception for unrecognized key names. To get the list of keys supported by this method, use babase.AppConfig.builtin_keys(). Note that it is perfectly legal to store other data in the config; it just needs to be accessed through standard dict methods and missing values handled manually.
- resolve(key: str) Any [source]¶
Given a string key, return a config value (type varies).
This will substitute application defaults for values not present in the config dict, filter some invalid values, etc. Note that these values do not represent the state of the app; simply the state of its config. Use the
App
class to access actual live state.Raises an
KeyError
for unrecognized key names. To get the list of keys supported by this method, usebuiltin_keys()
. Note that it is perfectly legal to store other data in the config; it just needs to be accessed through standard dict methods and missing values handled manually.
- class babase.AppHealthSubsystem[source]¶
Bases:
AppSubsystem
Subsystem for monitoring app health; logs not-responding issues, etc.
The single shared instance of this class can be found on the
health
attr on theApp
class.
- class babase.AppIntent[source]¶
Bases:
object
Base class for high level directives given to the app.
- class babase.AppIntentDefault[source]¶
Bases:
AppIntent
Tells the app to simply run in its default mode.
- class babase.AppIntentExec(code: str)[source]¶
Bases:
AppIntent
Tells the app to exec some Python code.
- class babase.AppMode[source]¶
Bases:
object
A low level mode the app can be in.
App-modes fundamentally change app behavior related to input handling, networking, graphics, and more. In a way, different app-modes can almost be considered different apps.
- classmethod can_handle_intent(intent: AppIntent) bool [source]¶
Return whether this mode can handle the provided intent.
For this to return True, the app-mode must claim to support the provided intent (via its
can_handle_intent_impl()
method) AND theAppExperience
associated with the app-mode must be supported by the current app and runtime environment.
- classmethod can_handle_intent_impl(intent: AppIntent) bool [source]¶
Override this to define indent handling for an app-mode.
Note that
AppExperience
does not have to be considered here; that is handled automatically by thecan_handle_intent()
call.
- classmethod get_app_experience() AppExperience [source]¶
Return the overall experience provided by this mode.
- on_app_active_changed() None [source]¶
Called when the app’s active state changes while in this app-mode.
This corresponds to the app’s
active
attr. App-active state becomes false when the app is hidden, minimized, backgrounded, etc. The app-mode may want to take action such as pausing a running game or saving state when this occurs.On platforms such as mobile where apps get suspended and later silently terminated by the OS, this is likely to be the last reliable place to save state/etc.
To best cover both mobile and desktop style platforms, actions such as saving state should generally happen in response to both
on_deactivate()
andon_app_active_changed()
(when active is False).
- on_deactivate() None [source]¶
Called when the mode stops being the active one for the app.
On platforms where the app is explicitly exited (such as desktop PC) this will also be called at app shutdown.
To best cover both mobile and desktop style platforms, actions such as saving state should generally happen in response to both
on_deactivate()
andon_app_active_changed()
(when active is False).
- class babase.AppModeSelector[source]¶
Bases:
object
Defines which app-modes should handle which app-intents.
The app calls an instance of this class when passed an
AppIntent
to determine whichAppMode
to use to handle it. Plugins or spinoff projects can modify high level app behavior by replacing or modifying the app’smode_selector
attr or by modifying settings used to construct the default one.
- class babase.AppState(*values)[source]¶
Bases:
Enum
High level state the app can be in.
- INITING = 2¶
Python app subsystems are being inited but should not yet interact or do any work.
- LOADING = 3¶
Python app subsystems are inited and interacting, but the app has not yet embarked on a high level course of action. It is doing initial account logins, workspace & asset downloads, etc.
- NATIVE_BOOTSTRAPPING = 1¶
The native layer is spinning up its machinery (screens, renderers, etc.). Nothing should happen in the Python layer until this completes.
- NOT_STARTED = 0¶
The app has not yet begun starting and should not be used in any way.
- RUNNING = 4¶
All pieces are in place and the app is now doing its thing.
- SHUTDOWN_COMPLETE = 7¶
The app has completed shutdown. Any code running here should be basically immediate.
- SHUTTING_DOWN = 6¶
The app is shutting down. This process may involve sending network messages or other things that can take up to a few seconds, so ideally graphics and audio should remain functional (with fades or spinners or whatever to show something is happening).
- SUSPENDED = 5¶
Used on platforms such as mobile where the app basically needs to shut down while backgrounded. In this state, all event loops are suspended and all graphics and audio must cease completely. Be aware that the suspended state can be entered from any other state including
NATIVE_BOOTSTRAPPING
andSHUTTING_DOWN
.
- class babase.AppSubsystem[source]¶
Bases:
object
Base class for an app subsystem.
An app ‘subsystem’ is a bit of a vague term, as pieces of the app can technically be any class and are not required to use this, but building one out of this base class provides conveniences such as predefined callbacks during app state changes.
Subsystems must be registered with the app before it completes its transition to the ‘running’ state.
- on_app_loading() None [source]¶
Called when the app reaches the loading state.
Note that subsystems created after the app switches to the loading state will not receive this callback. Subsystems created by plugins are an example of this.
- on_app_shutdown() None [source]¶
Called when app enters
SHUTTING_DOWN
state.
- on_app_shutdown_complete() None [source]¶
Called when app enters
SHUTDOWN_COMPLETE
state.
- on_screen_size_change() None [source]¶
Called when the screen size changes.
Will not be called for the initial screen size.
- class babase.AppTimer(time: float, call: Callable[[], Any], repeat: bool = False)[source]¶
Bases:
object
Timers are used to run code at later points in time.
This class encapsulates a timer based on app-time. The underlying timer will be destroyed when this object is no longer referenced. If you do not want to worry about keeping a reference to your timer around, use the
apptimer()
function instead to get a one-off timer.- Parameters:
time – Length of time in seconds that the timer will wait before firing.
call – A callable Python object. Remember that the timer will retain a strong reference to the callable for as long as it exists, so you may want to look into concepts such as
WeakCall
if that is not desired.repeat – If True, the timer will fire repeatedly, with each successive firing having the same delay as the first.
Example: Use a timer object to print repeatedly for a few seconds:
def say_it(): babase.screenmessage('BADGER!') def stop_saying_it(): global g_timer g_timer = None babase.screenmessage('MUSHROOM MUSHROOM!') # Create our timer; it will run as long as we keep its ref alive. g_timer = babase.AppTimer(0.3, say_it, repeat=True) # Now fire off a one-shot timer to kill the ref. babase.apptimer(3.89, stop_saying_it)
- class babase.Call(*args: Any, **keywds: Any)¶
Bases:
object
Wraps a callable and arguments into a single callable object.
The callable is strong-referenced so it won’t die until this object does.
Note that a bound method (ex:
myobj.dosomething
) contains a reference toself
(myobj
in that case), so you will be keeping that object alive too. Use babase.WeakCall if you want to pass a method to a callback without keeping its object alive.Example: Wrap a method call with 1 positional and 1 keyword arg:
mycall = babase.Call(myobj.dostuff, argval, namedarg=argval2) # Now we have a single callable to run that whole mess. # ..the same as calling myobj.dostuff(argval, namedarg=argval2) mycall()
- class babase.CloudSubscription(subscription_id: int)[source]¶
Bases:
object
User handle to a subscription to some cloud data.
Do not instantiate these directly; use the subscribe methods in
CloudSubsystem
to create them.
- class babase.ContextCall(call: Callable)[source]¶
Bases:
object
A context-preserving callable.
This wraps a callable object along with a reference to the current context (see
ContextRef
); it handles restoring the context when run and automatically clears itself if the context it belongs to dies.Generally you should not need to use this directly; all standard Ballistica callbacks involved with timers, materials, UI functions, etc. handle this under-the-hood so you don’t have to worry about it. The only time it may be necessary is if you are implementing your own callbacks, such as a worker thread that does some action and then runs some engine code when done. By wrapping said callback in one of these, you can ensure that you will not inadvertently be keeping the current activity alive or running code in a torn-down (expired)
ContextRef
.You can also use
WeakCall
for similar functionality, but ContextCall has the added bonus that it will not run duringContextRef
shutdown, whereasWeakCall
simply looks at whether the target object instance still exists.Example A: Code like this can inadvertently prevent our activity (self) from ending until the operation completes, since the bound method we’re passing (self.dosomething) contains a strong-reference to self):
start_some_long_action(callback_when_done=self.dosomething)
Example B: In this case our activity (self) can still die properly; the callback will clear itself when the activity starts shutting down, becoming a harmless no-op and releasing the reference to our activity:
start_long_action( callback_when_done=babase.ContextCall(self.mycallback))
- exception babase.ContextError[source]¶
Bases:
Exception
Raised when a call is made in an invalid context.
Examples of this include calling UI functions within an activity context or calling scene manipulation functions outside of a scene context.
- class babase.ContextRef[source]¶
Bases:
object
Store or use a Ballistica context.
Many operations such as
bascenev1.newnode()
orbascenev1.gettexture()
operate implicitly on a current ‘context’. A context is some sort of state that functionality can implicitly use. Context determines, for example, which scene new nodes or textures get added to without having to specify that explicitly in the newnode()/gettexture() call. Contexts can also affect object lifecycles; for example aContextCall
will instantly become a no-op and release any references it is holding when the context it belongs to is destroyed.In general, if you are a modder, you should not need to worry about contexts; mod code should mostly be getting run in the correct context and timers and other callbacks will take care of saving and restoring contexts automatically. There may be rare cases, however, where you need to deal directly with contexts, and that is where this class comes in.
Creating a context-ref will capture a reference to the current context. Other modules may provide ways to access their contexts; for example a
bascenev1.Activity
instance has acontext
attribute. You can also use theempty()
classmethod to create a reference to no context. Some code such as UI calls may expect to be run with no context set and may complain if you try to use them within a context.Usage¶
Context-refs are generally used with the Python
with
statement, which sets the context they point to as current on entry and resets it to the previous value on exit.Example: Explicitly clear context while working with UI code from gameplay (UI stuff may complain if called within a context):
import bauiv1 as bui def _callback_called_from_gameplay(): # We are probably called with a game context as current, but # this makes UI stuff unhappy. So we clear the context while # doing our thing. with bui.ContextRef.empty(): my_container = bui.containerwidget()
- classmethod empty() ContextRef [source]¶
Return a context-ref pointing to no context.
This is useful when code should be run free of a context. For example, UI code generally insists on being run this way. Otherwise, callbacks set on the UI could inadvertently stop working due to a game activity ending, which would be unintuitive behavior.
- exception babase.DelegateNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected delegate object does not exist.
- class babase.DevConsoleSubsystem[source]¶
Bases:
object
Subsystem for wrangling the dev-console.
Access the single shared instance of this class via the
devconsole
attr on theApp
class. The dev-console is a simple always-available UI intended for use by developers; not end users. Traditionally it is available by typing a backtick (`) key on a keyboard, but can also be accessed via an on-screen button (see settings/advanced/dev-tools to enable said button).- tabs: list[DevConsoleTabEntry]¶
All tabs in the dev-console. Add your own stuff here via plugins or whatnot to customize the console.
- class babase.DevConsoleTab[source]¶
Bases:
object
Base class for a
DevConsoleSubsystem
tab.- property base_scale: float¶
A scale value based on the app’s current
UIScale
.Dev-console tabs can manually incorporate this into their UI sizes and positions if they desire. By default, dev-console tabs are uniform across all ui-scales.
- button(label: str, pos: tuple[float, float], size: tuple[float, float], call: Callable[[], Any] | None = None, *, h_anchor: Literal['left', 'center', 'right'] = 'center', label_scale: float = 1.0, corner_radius: float = 8.0, style: Literal['normal', 'bright', 'red', 'red_bright', 'purple', 'purple_bright', 'yellow', 'yellow_bright', 'blue', 'blue_bright', 'white', 'white_bright', 'black', 'black_bright'] = 'normal', disabled: bool = False) None [source]¶
Add a button to the tab being refreshed.
- refresh() None [source]¶
Called when the tab should refresh itself.
Overridden by subclasses to implement tab behavior.
- class babase.DevConsoleTabEntry(name: str, factory: Callable[[], DevConsoleTab])[source]¶
Bases:
object
Represents a distinct tab in the
DevConsoleSubsystem
.- factory: Callable[[], DevConsoleTab]¶
- class babase.DisplayTimer(time: float, call: Callable[[], Any], repeat: bool = False)[source]¶
Bases:
object
Timers are used to run code at later points in time.
This class encapsulates a timer based on display-time. The underlying timer will be destroyed when this object is no longer referenced. If you do not want to worry about keeping a reference to your timer around, use the
displaytimer()
function instead to get a one-off timer.Display-time is a time value intended to be used for animation and other visual purposes. It will generally increment by a consistent amount each frame. It will pass at an overall similar rate to AppTime, but trades accuracy for smoothness.
- Parameters:
time – Length of time in seconds that the timer will wait before firing.
call – A callable Python object. Remember that the timer will retain a strong reference to the callable for as long as it exists, so you may want to look into concepts such as
WeakCall
if that is not desired.repeat – If True, the timer will fire repeatedly, with each successive firing having the same delay as the first.
Example: Use a Timer object to print repeatedly for a few seconds:
def say_it(): babase.screenmessage('BADGER!') def stop_saying_it(): global g_timer g_timer = None babase.screenmessage('MUSHROOM MUSHROOM!') # Create our timer; it will run as long as we keep its ref alive. g_timer = babase.DisplayTimer(0.3, say_it, repeat=True) # Now fire off a one-shot timer to kill the ref. babase.displaytimer(3.89, stop_saying_it)
- class babase.Env[source]¶
Bases:
object
Unchanging values for the current running app instance. Access the single shared instance of this class through the
env
attr on theApp
class.- api_version: int¶
The app’s api version.
Only Python modules and packages associated with the current API version number will be detected by the game (see the
babase.MetadataSubsystem
). This value will change whenever substantial backward-incompatible changes are introduced to Ballistica APIs. When that happens, modules/packages should be updated accordingly and set to target the newer API version number.
- debug: bool¶
Whether the app is running in debug mode.
Debug builds generally run substantially slower than non-debug builds due to compiler optimizations being disabled and extra checks being run.
- engine_build_number: int¶
Integer build number for the engine.
This value increases by at least 1 with each release of the engine. It is independent of the human readable version string.
- engine_version: str¶
Human-readable version string for the engine; something like ‘1.3.24’.
This should not be interpreted as a number; it may contain string elements such as ‘alpha’, ‘beta’, ‘test’, etc. If a numeric version is needed, use build_number.
- python_directory_app: str | None¶
Path where the app expects its bundled modules to live.
Be aware that this value may be None if Ballistica is running in a non-standard environment, and that python-path modifications may cause modules to be loaded from other locations.
- python_directory_app_site: str | None¶
Path where the app expects its bundled pip modules to live.
Be aware that this value may be None if Ballistica is running in a non-standard environment, and that python-path modifications may cause modules to be loaded from other locations.
- python_directory_user: str | None¶
Path where the app expects its user scripts (mods) to live.
Be aware that this value may be None if Ballistica is running in a non-standard environment, and that python-path modifications may cause modules to be loaded from other locations.
- supports_soft_quit: bool¶
Whether the running app supports ‘soft’ quit options.
This generally applies to mobile derived OSs, where an act of ‘quitting’ may leave the app running in the background waiting in case it is used again.
- class babase.Existable(*args, **kwargs)[source]¶
Bases:
Protocol
A Protocol for objects supporting an exists() method.
- exception babase.InputDeviceNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected input-device does not exist.
- class babase.InputType(*values)[source]¶
Bases:
Enum
Types of input a controller can send to the game.
- BOMB_PRESS = 8¶
- BOMB_RELEASE = 9¶
- DOWN_PRESS = 25¶
- DOWN_RELEASE = 26¶
- FLY_PRESS = 13¶
- FLY_RELEASE = 14¶
- HOLD_POSITION_PRESS = 17¶
- HOLD_POSITION_RELEASE = 18¶
- JUMP_PRESS = 4¶
- JUMP_RELEASE = 5¶
- LEFT_PRESS = 19¶
- LEFT_RELEASE = 20¶
- LEFT_RIGHT = 3¶
- PICK_UP_PRESS = 10¶
- PICK_UP_RELEASE = 11¶
- PUNCH_PRESS = 6¶
- PUNCH_RELEASE = 7¶
- RIGHT_PRESS = 21¶
- RIGHT_RELEASE = 22¶
- RUN = 12¶
- START_PRESS = 15¶
- START_RELEASE = 16¶
- UP_DOWN = 2¶
- UP_PRESS = 23¶
- UP_RELEASE = 24¶
- class babase.LanguageSubsystem[source]¶
Bases:
AppSubsystem
Language functionality for the app.
Access the single instance of this class at ‘babase.app.lang’.
- property available_languages: list[str]¶
A list of all available languages.
Note that languages that may be present in game assets but which are not displayable on the running version of the game are not included here.
- get_resource(resource: str, fallback_resource: str | None = None, fallback_value: Any = None) Any [source]¶
Return a translation resource by name.
Warning
Use
Lstr
instead of this function whenever possible, as it will gracefully handle displaying correctly across multiple clients in multiple languages simultaneously.
- is_custom_unicode_char(char: str) bool [source]¶
Return whether a char is in the custom unicode range we use.
- property language: str¶
The current active language for the app.
This can be selected explicitly by the user or may be set automatically based on locale or other factors.
- property locale: str¶
Raw country/language code detected by the game (such as “en_US”).
Generally for language-specific code you should look at
language
, which is the language the game is using (which may differ from locale if the user sets a language, etc.)
- setlanguage(language: str | dict | None, print_change: bool = True, store_to_config: bool = True) None [source]¶
Set the active app language.
Pass None to use OS default language.
- testlanguage(langid: str) None [source]¶
Set the app to test an in-progress language.
Pass a language id from the translation editor website as ‘langid’; something like ‘Gibberish_3263’. Once set to testing, the engine will repeatedly download and apply that same test language, so changes can be made to it and observed live.
- translate(category: str, strval: str, raise_exceptions: bool = False, print_errors: bool = False) str [source]¶
Translate a value (or return the value if no translation available)
Warning
Use
Lstr
instead of this function whenever possible, as it will gracefully handle displaying correctly across multiple clients in multiple languages simultaneously.
- class babase.LoginAdapter(login_type: LoginType)[source]¶
Bases:
object
Allows using implicit login types in an explicit way.
Some login types such as Google Play Game Services or Game Center are basically always present and often do not provide a way to log out from within a running app, so this adapter exists to use them in a flexible manner by ‘attaching’ and ‘detaching’ from an always-present login, allowing for its use alongside other login types. It also provides common functionality for server-side account verification and other handy bits.
- class ImplicitLoginState(login_id: str, display_name: str)[source]¶
Bases:
object
Describes the current state of an implicit login.
- class SignInResult(credentials: str)[source]¶
Bases:
object
Describes the final result of a sign-in attempt.
- get_sign_in_token(completion_cb: Callable[[str | None], None]) None [source]¶
Get a sign-in token from the adapter back end.
This token is then passed to the cloud to complete the sign-in process. The adapter can use this opportunity to bring up account creation UI, call its internal sign-in function, etc. as needed. The provided
completion_cb
should then be called with either a token or withNone
if sign in failed or was cancelled.
- on_back_end_active_change(active: bool) None [source]¶
Called when active state for the back-end is (possibly) changing.
Meant to be overridden by subclasses. Being active means that the implicit login provided by the back-end is actually being used by the app. It should therefore register unlocked achievements, leaderboard scores, allow viewing native UIs, etc. When not active it should ignore everything and behave as if signed out, even if it technically is still signed in.
- set_implicit_login_state(state: ImplicitLoginState | None) None [source]¶
Keep the adapter informed of implicit login states.
This should be called by the adapter back-end when an account of their associated type gets logged in or out.
- sign_in(result_cb: Callable[[LoginAdapter, SignInResult | Exception], None], description: str) None [source]¶
Attempt to sign in via this adapter.
This can be called even if the back-end is not implicitly signed in; the adapter will attempt to sign in if possible. An exception will be passed to the callback if the sign-in attempt fails.
- class babase.LoginInfo(name: str)[source]¶
Bases:
object
Info for a login used by
AccountV2Handle
.
- class babase.Lstr(*, resource: str, fallback_resource: str = '', fallback_value: str = '', subs: Sequence[tuple[str, str | Lstr]] | None = None)[source]¶
- class babase.Lstr(*, translate: tuple[str, str], subs: Sequence[tuple[str, str | Lstr]] | None = None)
- class babase.Lstr(*, value: str, subs: Sequence[tuple[str, str | Lstr]] | None = None)
Bases:
object
Used to define strings in a language-independent way.
These should be used whenever possible in place of hard-coded strings so that in-game or UI elements show up correctly on all clients in their currently active language.
To see available resource keys, look at any of the
ba_data/data/languages/*.json
files in the game or the translations pages at legacy.ballistica.net/translate.- Parameters:
resource – Pass a string to look up a translation by resource key.
translate – Pass a tuple consisting of a translation category and untranslated value. Any matching translation found in that category will be used. Otherwise the untranslated value will be.
value – Pass a regular string value to be used as-is.
subs – A sequence of 2-member tuples consisting of values and replacements. Replacements can be regular strings or other
Lstr
values.fallback_resource – A resource key that will be used if the main one is not present for the current language instead of falling back to the english value (‘resource’ mode only).
fallback_value – A regular string that will be used if neither the resource nor the fallback resource is found (‘resource’ mode only).
Example 1: Resource path
mynode.text = babase.Lstr(resource='audioSettingsWindow.titleText')
Example 2: Translation
If a translated value is available, it will be used; otherwise the English value will be. To see available translation categories, look under the
translations
resource section.mynode.text = babase.Lstr(translate=('gameDescriptions', 'Defeat all enemies'))
Example 3: Substitutions
Substitutions can be used with
resource
andtranslate
modes as well as thevalue
shown here.mynode.text = babase.Lstr(value='${A} / ${B}', subs=[('${A}', str(score)), ('${B}', str(total))])
Example 4: Nesting
Lstr
instances can be nested. This example would display the translated resource at'res_a'
but replace any instances of'${NAME}'
it contains with the translated resource at'res_b'
.mytextnode.text = babase.Lstr( resource='res_a', subs=[('${NAME}', babase.Lstr(resource='res_b'))])
- args¶
Basically just stores the exact args passed. However if Lstr values were passed for subs, they are replaced with that Lstr’s dict.
- evaluate() str [source]¶
Evaluate to a flat string in the current language.
You should avoid doing this as much as possible and instead pass and store
Lstr
values.
- static from_json(json_string: str) babase.Lstr [source]¶
Given a json string, returns a
Lstr
.Does no validation.
- is_flat_value() bool [source]¶
Return whether this instance represents a ‘flat’ value.
This is defined as a simple string value incorporating no translations, resources, or substitutions. In this case it may be reasonable to replace it with a raw string value, perform string manipulation on it, etc.
- exception babase.MapNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected map does not exist.
- class babase.MetadataSubsystem[source]¶
Bases:
object
Subsystem for working with script metadata in the app.
Access the single shared instance of this class via the
meta
attr on theApp
class.- load_exported_classes(cls: type[T], completion_cb: Callable[[list[type[T]]], None], completion_cb_in_bg_thread: bool = False) None [source]¶
High level function to load meta-exported classes.
Will wait for scanning to complete if necessary, and will load all registered classes of a particular type in a background thread before calling the passed callback in the logic thread. Errors may be logged to messaged to the user in some way but the callback will be called regardless. To run the completion callback directly in the bg thread where the loading work happens, pass
completion_cb_in_bg_thread=True
.
- exception babase.NodeNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected node does not exist.
- exception babase.NotFoundError[source]¶
Bases:
Exception
Raised when a referenced object does not exist.
- class babase.Permission(*values)[source]¶
Bases:
Enum
Permissions that can be requested from the OS.
- STORAGE = 0¶
- exception babase.PlayerNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected player does not exist.
- class babase.Plugin[source]¶
Bases:
object
A plugin to alter app behavior in some way.
Plugins are discoverable by the
MetadataSubsystem
system and the user can select which ones they want to enable. Enabled plugins are then called at specific times as the app is running in order to modify its behavior in some way.
- class babase.PluginSpec(class_path: str, loadable: bool)[source]¶
Bases:
object
Represents a plugin the engine knows about.
- attempted_load¶
Whether the engine has attempted to load the plugin. If this is True but the value of
plugin
is None, it means there was an error loading the plugin. If a plugin’s api-version does not match the running app, if a new plugin is detected with auto-enable-plugins disabled, or if the user has explicitly disabled a plugin, the engine will not even attempt to load it.
- class_path¶
Fully qualified class path for the plugin.
- property enabled: bool¶
Whether this plugin is set to load.
Getting or setting this attr affects the corresponding app-config key. Remember to commit the app-config after making any changes.
- loadable¶
Can we attempt to load the plugin?
- class babase.PluginSubsystem[source]¶
Bases:
AppSubsystem
Subsystem for wrangling plugins.
Access the single shared instance of this class via the
plugins
attr on theApp
class.- active_plugins: list[babase.Plugin]¶
The set of live active plugin instances.
- plugin_specs: dict[str, babase.PluginSpec]¶
Info about plugins that we are aware of. This may include plugins discovered through meta-scanning as well as plugins registered in the app-config. This may include plugins that cannot be loaded for various reasons or that have been intentionally disabled.
- class babase.QuitType(*values)[source]¶
Bases:
Enum
Types of quit behavior that can be requested from the app.
- ‘soft’ may hide/reset the app but keep the process running, depending
on the platform (generally a thing on mobile).
- ‘back’ is a variant of ‘soft’ which may give ‘back-button-pressed’
behavior depending on the platform. (returning to some previous activity instead of dumping to the home screen, etc.)
- ‘hard’ leads to the process exiting. This generally should be avoided
on platforms such as mobile where apps are expected to keep running until killed by the OS.
- BACK = 1¶
- HARD = 2¶
- SOFT = 0¶
- exception babase.SessionNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected session does not exist.
- exception babase.SessionPlayerNotFoundError[source]¶
Bases:
NotFoundError
Exception raised when an expected session-player does not exist.
- exception babase.SessionTeamNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected session-team does not exist.
- class babase.SpecialChar(*values)[source]¶
Bases:
Enum
Special characters the game can print.
- BACK = 10¶
- BOTTOM_BUTTON = 7¶
- CROWN = 64¶
- DELETE = 8¶
- DICE_BUTTON1 = 31¶
- DICE_BUTTON2 = 32¶
- DICE_BUTTON3 = 33¶
- DICE_BUTTON4 = 34¶
- DOWN_ARROW = 0¶
- DPAD_CENTER_BUTTON = 15¶
- DRAGON = 69¶
- EXPLODINARY_LOGO = 46¶
- EYE_BALL = 66¶
- FAST_FORWARD_BUTTON = 14¶
- FEDORA = 62¶
- FIREBALL = 76¶
- FLAG_ALGERIA = 81¶
- FLAG_ARGENTINA = 92¶
- FLAG_AUSTRALIA = 85¶
- FLAG_BRAZIL = 50¶
- FLAG_CANADA = 54¶
- FLAG_CHILE = 94¶
- FLAG_CHINA = 52¶
- FLAG_CZECH_REPUBLIC = 84¶
- FLAG_EGYPT = 79¶
- FLAG_FRANCE = 57¶
- FLAG_GERMANY = 49¶
- FLAG_INDIA = 55¶
- FLAG_INDONESIA = 58¶
- FLAG_IRAN = 90¶
- FLAG_ITALY = 59¶
- FLAG_JAPAN = 56¶
- FLAG_KUWAIT = 80¶
- FLAG_MALAYSIA = 83¶
- FLAG_MEXICO = 48¶
- FLAG_NETHERLANDS = 61¶
- FLAG_PHILIPPINES = 93¶
- FLAG_POLAND = 91¶
- FLAG_QATAR = 78¶
- FLAG_RUSSIA = 51¶
- FLAG_SAUDI_ARABIA = 82¶
- FLAG_SINGAPORE = 86¶
- FLAG_SOUTH_KOREA = 60¶
- FLAG_UNITED_ARAB_EMIRATES = 77¶
- FLAG_UNITED_KINGDOM = 53¶
- FLAG_UNITED_STATES = 47¶
- GAME_CENTER_LOGO = 30¶
- GAME_CIRCLE_LOGO = 35¶
- GOOGLE_PLAY_GAMES_LOGO = 29¶
- HAL = 63¶
- HEART = 68¶
- HELMET = 70¶
- LEFT_ARROW = 2¶
- LEFT_BUTTON = 5¶
- LOCAL_ACCOUNT = 45¶
- LOGO = 27¶
- LOGO_FLAT = 11¶
- MIKIROG = 95¶
- MOON = 74¶
- MUSHROOM = 71¶
- NINJA_STAR = 72¶
- NVIDIA_LOGO = 89¶
- OCULUS_LOGO = 87¶
- OUYA_BUTTON_A = 25¶
- OUYA_BUTTON_O = 22¶
- OUYA_BUTTON_U = 23¶
- OUYA_BUTTON_Y = 24¶
- PARTY_ICON = 36¶
- PAUSE_BUTTON = 21¶
- PLAY_BUTTON = 20¶
- PLAY_PAUSE_BUTTON = 13¶
- PLAY_STATION_CIRCLE_BUTTON = 17¶
- PLAY_STATION_CROSS_BUTTON = 16¶
- PLAY_STATION_SQUARE_BUTTON = 19¶
- PLAY_STATION_TRIANGLE_BUTTON = 18¶
- REWIND_BUTTON = 12¶
- RIGHT_ARROW = 3¶
- RIGHT_BUTTON = 6¶
- SHIFT = 9¶
- SKULL = 67¶
- SPIDER = 75¶
- STEAM_LOGO = 88¶
- TEST_ACCOUNT = 37¶
- TICKET = 28¶
- TICKET_BACKING = 38¶
- TOKEN = 26¶
- TOP_BUTTON = 4¶
- TROPHY0A = 42¶
- TROPHY0B = 43¶
- TROPHY1 = 39¶
- TROPHY2 = 40¶
- TROPHY3 = 41¶
- TROPHY4 = 44¶
- UP_ARROW = 1¶
- V2_LOGO = 96¶
- VIKING_HELMET = 73¶
- YIN_YANG = 65¶
- class babase.StringEditAdapter(description: str, initial_text: str, max_length: int | None, screen_space_center: tuple[float, float] | None)[source]¶
Bases:
object
Represents a string editing operation on some object.
Editable objects such as text widgets or in-app-consoles can subclass this to make their contents editable on all platforms.
There can only be one string-edit at a time for the app. New string-edits will attempt to register themselves as the globally active one in their constructor, but this may not succeed. If
can_be_replaced()
returnsTrue
for an adapter immediately after creating it, that means it was not able to set itself as the global one.- apply(new_text: str) None [source]¶
Should be called by the owner when editing is complete.
Note that in some cases this call may be a no-op (such as if this adapter is no longer the globally active one).
- class babase.StringEditSubsystem[source]¶
Bases:
object
Full string-edit state for the app.
Access the single shared instance of this class via the
stringedit
attr on theApp
class.
- exception babase.TeamNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected team does not exist.
- class babase.UIScale(*values)[source]¶
Bases:
Enum
The overall scale the UI is being rendered for. Note that this is independent of pixel resolution. For example, a phone and a desktop PC might render the game at similar pixel resolutions but the size they display content at will vary significantly.
- ‘large’ is used for devices such as desktop PCs where fine details can
be clearly seen. UI elements are generally smaller on the screen and more content can be seen at once.
- ‘medium’ is used for devices such as tablets, TVs, or VR headsets.
This mode strikes a balance between clean readability and amount of content visible.
- ‘small’ is used primarily for phones or other small devices where
content needs to be presented as large and clear in order to remain readable from an average distance.
- LARGE = 2¶
- MEDIUM = 1¶
- SMALL = 0¶
- class babase.Vec3[source]¶
- class babase.Vec3(value: float)
- class babase.Vec3(values: Sequence[float])
- class babase.Vec3(x: float, y: float, z: float)
-
A vector of 3 floats.
- These can be created the following ways (checked in this order):
With no args, all values are set to 0.
With a single numeric arg, all values are set to that value.
With a three-member sequence arg, sequence values are copied.
Otherwise assumes individual x/y/z args (positional or keywords).
- class babase.WeakCall(*args: Any, **keywds: Any)¶
Bases:
object
Wrap a callable and arguments into a single callable object.
When passed a bound method as the callable, the instance portion of it is weak-referenced, meaning the underlying instance is free to die if all other references to it go away. Should this occur, calling the weak-call is simply a no-op.
Think of this as a handy way to tell an object to do something at some point in the future if it happens to still exist.
EXAMPLE A: This code will create a
FooClass
instance and call itsbar()
method 5 seconds later; it will be kept alive even though we overwrite its variable with None because the bound method we pass as a timer callback (foo.bar
) strong-references it:foo = FooClass() babase.apptimer(5.0, foo.bar) foo = None
EXAMPLE B: This code will not keep our object alive; it will die when we overwrite it with
None
and the timer will be a no-op when it fires:foo = FooClass() babase.apptimer(5.0, ba.WeakCall(foo.bar)) foo = None
EXAMPLE C: Wrap a method call with some positional and keyword args:
myweakcall = babase.WeakCall(self.dostuff, argval1, namedarg=argval2) # Now we have a single callable to run that whole mess. # The same as calling myobj.dostuff(argval1, namedarg=argval2) # (provided my_obj still exists; this will do nothing otherwise). myweakcall()
Note: additional args and keywords you provide to the weak-call constructor are stored as regular strong-references; you’ll need to wrap them in weakrefs manually if desired.
- exception babase.WidgetNotFoundError[source]¶
Bases:
NotFoundError
Raised when an expected widget does not exist.
- babase.apptime() babase.AppTime [source]¶
Return the current app-time in seconds.
App-time is a monotonic time value; it starts at 0.0 when the app launches and will never jump by large amounts or go backwards, even if the system time changes. Its progression will pause when the app is in a suspended state.
Note that the AppTime returned here is simply float; it just has a unique type in the type-checker’s eyes to help prevent it from being accidentally used with time functionality expecting other time types.
- babase.apptimer(time: float, call: Callable[[], Any]) None [source]¶
Schedule a callable object to run based on app-time.
This function creates a one-off timer which cannot be canceled or modified once created. If you require the ability to do so, or need a repeating timer, use the babase.AppTimer class instead.
- Parameters:
time – Length of time in seconds that the timer will wait before firing.
call – A callable Python object. Note that the timer will retain a strong reference to the callable for as long as the timer exists, so you may want to look into concepts such as
WeakCall
if that is not desired.
Example: Print some stuff through time:
import babase babase.screenmessage('hello from now!') babase.apptimer(1.0, babase.Call(babase.screenmessage, 'hello from the future!')) babase.apptimer(2.0, babase.Call(babase.screenmessage, 'hello from the future 2!'))
- babase.can_display_chars(text: str) bool [source]¶
Is this build able to display all chars in the provided string?
See also:
supports_unicode_display()
.
- babase.charstr(char_id: babase.SpecialChar) str [source]¶
Return a unicode string representing a special character.
Note that these utilize the private-use block of unicode characters (U+E000-U+F8FF) and are specific to the game; exporting or rendering them elsewhere will be meaningless.
See
SpecialChar
for the list of available characters.
- babase.clipboard_get_text() str [source]¶
Return text currently on the system clipboard.
Ensure that
clipboard_has_text()
returns True before calling this function.
- babase.clipboard_has_text() bool [source]¶
Return whether there is currently text on the clipboard.
- This will return False if no system clipboard is available; no need
to call
clipboard_is_supported()
separately.
- babase.clipboard_is_supported() bool [source]¶
Return whether this platform supports clipboard operations at all.
If this returns False, UIs should not show ‘copy to clipboard’ buttons, etc.
- babase.clipboard_set_text(value: str) None [source]¶
Copy a string to the system clipboard.
Ensure that
clipboard_is_supported()
returns True before adding buttons/etc. that make use of this functionality.
- babase.displaytime() babase.DisplayTime [source]¶
Return the current display-time in seconds.
Display-time is a time value intended to be used for animation and other visual purposes. It will generally increment by a consistent amount each frame. It will pass at an overall similar rate to app-time, but trades accuracy for smoothness.
Note that the value returned here is simply a float; it just has a unique type in the type-checker’s eyes to help prevent it from being accidentally used with time functionality expecting other time types.
- babase.displaytimer(time: float, call: Callable[[], Any]) None [source]¶
Schedule a callable object to run based on display-time.
This function creates a one-off timer which cannot be canceled or modified once created. If you require the ability to do so, or need a repeating timer, use the
DisplayTimer
class instead.Display-time is a time value intended to be used for animation and other visual purposes. It will generally increment by a consistent amount each frame. It will pass at an overall similar rate to app-time, but trades accuracy for smoothness.
- Parameters:
time – Length of time in seconds that the timer will wait before firing.
call – A callable Python object. Note that the timer will retain a strong reference to the callable for as long as the timer exists, so you may want to look into concepts such as
WeakCall
if that is not desired.
Example: Print some stuff through time:
babase.screenmessage('hello from now!') babase.displaytimer(1.0, babase.Call(babase.screenmessage, 'hello from the future!')) babase.displaytimer(2.0, babase.Call(babase.screenmessage, 'hello from the future 2!'))
- babase.do_once() bool [source]¶
Return whether this is the first time running a line of code.
This is used by
print_once()
type calls to keep from overflowing logs. The call functions by registering the filename and line where The call is made from. Returns True if this location has not been registered already, and False if it has.Example: This print will only fire for the first loop iteration:
for i in range(10): if babase.do_once(): print('HelloWorld once from loop!')
- babase.existing(obj: ExistableT | None) ExistableT | None [source]¶
Convert invalid references to None for any babase.Existable object.
To best support type checking, it is important that invalid references not be passed around and instead get converted to values of None. That way the type checker can properly flag attempts to pass possibly-dead objects (
FooType | None
) into functions expecting only live ones (FooType
), etc. This call can be used on any ‘existable’ object (one with anexists()
method) and will convert it to aNone
value if it does not exist.For more info, see notes on ‘existables’ here: https://ballistica.net/wiki/Coding-Style-Guide
- babase.fatal_error(message: str) None [source]¶
Trigger a fatal error. Use this in situations where it is not possible for the engine to continue on in a useful way. This can sometimes help provide more clear information at the exact source of a problem as compared to raising an
Exception
. In the vast majority of cases, however, exceptions should be preferred.
- babase.get_ip_address_type(addr: str) AddressFamily [source]¶
Return an address-type given an address.
Can be
socket.AF_INET
orsocket.AF_INET6
.
- babase.get_virtual_safe_area_size() tuple[float, float] [source]¶
Return the size of the area on screen that will always be visible.
- babase.get_virtual_screen_size() tuple[float, float] [source]¶
Return the current virtual size of the display.
- babase.getclass(name: str, subclassof: type[T], check_sdlib_modulename_clash: bool = False) type[T] [source]¶
Given a full class name such as
foo.bar.MyClass
, return the class.The class will be checked to make sure it is a subclass of the provided ‘subclassof’ class, and a
TypeError
will be raised if not.
- babase.in_logic_thread() bool [source]¶
Return whether the current thread is the logic thread.
The logic thread is where a large amount of app code runs, and various functionality expects to only be used from there.
- babase.is_browser_likely_available() bool [source]¶
Return whether a browser likely exists on the current device.
If this returns False, you may want to avoid calling
open_url()
with any lengthy addresses. (open_url()
will display an address as a string/qr-code in a window if unable to bring up a browser, but that is only reasonable for small-ish URLs.)
- babase.native_stack_trace() str | None [source]¶
Return a native stack trace as a string, or None if not available.
Stack traces contain different data and formatting across platforms. Only use them for debugging.
- babase.normalized_color(color: Sequence[float]) tuple[float, ...] [source]¶
Scale a color so its largest value is 1.0; useful for coloring lights.
- babase.open_url(address: str, force_fallback: bool = False) None [source]¶
Open the provided URL.
Attempts to open the provided url in a web-browser. If that is not possible (or
force_fallback
is True), instead displays the url as a string and/or qrcode.
- babase.pushcall(call: Callable, from_other_thread: bool = False, suppress_other_thread_warning: bool = False, other_thread_use_fg_context: bool = False, raw: bool = False) None [source]¶
Push a call to the logic-thread’s event loop.
This function expects to be called from the logic thread, and will automatically save and restore the context to behave seamlessly.
To push a call from outside of the logic thread, pass
from_other_thread=True
. In that case the call will run with no context set. To instead run in whichever context is currently active on the logic thread, passother_thread_use_fg_context=True
. Passingraw=True
will skip thread checks and context saves/restores altogether.
- babase.quit(confirm: bool = False, quit_type: babase.QuitType | None = None) None [source]¶
Quit the app.
If
confirm
is True, a confirm dialog will be presented if conditions allow; otherwise the quit will still be immediate. See docs forQuitType
for explanations of the optionalquit_type
arg.
- babase.safecolor(color: Sequence[float], target_intensity: float = 0.6) tuple[float, ...] [source]¶
Given a color tuple, return a color safe to display as text.
Accepts tuples of length 3 or 4. This will slightly brighten very dark colors, etc.
- babase.screenmessage(message: str | babase.Lstr, color: Sequence[float] | None = None, log: bool = False) None [source]¶
Print a message to the local client’s screen in a given color.
Note that this function is purely for local display. To broadcast screen-messages during gameplay, look for methods such as
bascenev1.broadcastmessage()
.
- babase.storagename(suffix: str | None = None) str [source]¶
Generate a unique name for storing class data in shared places.
This consists of a leading underscore, the module path at the call site with dots replaced by underscores, the containing class’s qualified name, and the provided suffix. When storing data in public places such as ‘customdata’ dicts, this minimizes the chance of collisions with other similarly named classes.
Note that this will function even if called in the class definition.
Example: Generate a unique name for storage purposes:
class MyThingie: # This will give something like # '_mymodule_submodule_mythingie_data'. _STORENAME = babase.storagename('data') # Use that name to store some data in the Activity we were # passed. def __init__(self, activity): activity.customdata[self._STORENAME] = {}
- babase.supports_unicode_display() bool [source]¶
Return whether we can display all unicode characters in the gui.
- babase.timestring(timeval: float | int, centi: bool = True) babase.Lstr [source]¶
Generate a localized string for displaying a time value.
Given a time value, returns a localized string with: (hours if > 0 ) : minutes : seconds : (centiseconds if centi=True).
Warning
the underlying localized-string value is somewhat large, so don’t use this to rapidly update text values for an in-game timer or you may consume significant network bandwidth. For that sort of thing you should use things like ‘timedisplay’ nodes and attribute connections.
- babase.utc_now_cloud() datetime.datetime [source]¶
Returns estimated utc time regardless of local clock settings.
Applies offsets pulled from server communication/etc.
- babase.verify_object_death(obj: object) None [source]¶
Warn if an object does not get freed within a short period.
This can be handy to detect and prevent memory/resource leaks.
Submodules¶
babase.modutils module¶
Functionality related to modding.
- babase.modutils.create_user_system_scripts() None [source]¶
Set up a copy of Ballistica app scripts under user scripts dir.
(for editing and experimenting)
- babase.modutils.delete_user_system_scripts() None [source]¶
Clean out the scripts created by create_user_system_scripts().