Region connectivity checker and general net cleanup

This commit is contained in:
Eric Froemling 2021-04-28 09:44:08 -05:00
parent 09f5b49ab2
commit d79683a5b3
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
11 changed files with 100 additions and 83 deletions

View File

@ -3932,40 +3932,40 @@
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450", "assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e", "assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/6f/0093308b03e214a39240a11a89ef", "build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ce/05/ca46e7d32db9365adf5b8bfba176",
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f2/81/719068599c72d85cfb80bda5cdf4", "build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/94/d59852c21cc8fbd77a5f3fcd3874",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/c6/b3320e2b4566b04d6f5949c88a8e", "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/4b/30e4b3a62d6ddc31200bf68bed96",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6d/ef/bb96c465d5eb16d0fec47a03148f", "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6b/d9/ea08e2b748b7abb7ab9b1022fb6d",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/02/b7/d3e9ed995a399994c1fb19d956c8", "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d7/21/97fbbbae1b0c1187f0aa024dc5cf",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/07/97/b504f8fd31c06d68486e7ccb0387", "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/a2/df6f4a0821e58c08cbf5ffc09fcc",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b6/e6/090cccc0d929e087d2aab57d9dac", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2e/de/b8faaef1cdf126911bd1af5fe04c",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/c9/7d5b3ac4a43b7b0aec0f5cdabd79", "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4b/ed/f39044c89a5ce40a8999536f640c",
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/3a/9e92efd73aba4518b9b8263034f0", "build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ad/58/28e31902f10e078b04537370a46b",
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/f2/68b51355c2be03c4e2298b2906e5", "build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c5/bd/7944d5d24cdf46207013c36374f6",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b1/f7/b7d941d6e981808cf4f2e6d36583", "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/39/4f979e4ac2c3bf9a484771cb31e9",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/32/c8eb65a172687cbf8b5c31d21a7c", "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/3f/ac7523ec734c09b637f45adc73b3",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fb/aa/ae2ba68cb21ffb87094b35d3fbb5", "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2b/d4/8faf40e2e036f69ac96408a14a5a",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/8e/4bfa47ec0b686b9c562cdb025865", "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/71/9ffd5ced8c3834c73ca8b6a3f04d",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/09/3a25529f46207559209d501f9258", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/12/20/1145c90452a44bf985cf2feca3dc",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/29/bfed043d9579ec5a6f8aee61ee2c", "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/ad/810a83e0b053550f730d02061845",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a5/93/d3d0cad213af8458bf51b1f50518", "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9d/a4/418733dbbd677aa0cd28cd5101c9",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/73/46/0c6cdc30f65794bee7ca6176f99e", "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c8/f3/ad02c475133e4a82620bd840a8c3",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dc/0f/5b3ae48dfd447d9b2f0bf739001f", "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/41/c9/dc5db16b82429639ad51b4bd2248",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d2/fa/e926513494f2f5e179ef1efab273", "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ef/ff/2e12d7939319a700a5561ddeec18",
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/44/58/9661a59dfa92221062162488e8b6", "build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/05/1d/03a2b2487e67010afff2a855fa2e",
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f8/33/98bf3a52dfb29efe303f90068c86", "build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7c/8e/4be856155b5485c6a2ed8a605253",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/49/44/26db0fadff080ea5d9f5a0662f2c", "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a6/7d/a267f67eb9c9eecc0c6c5d4381c4",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/78/9b/b5ed834f977f00a12e83e6a72ac3", "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/de/1e/f74bbd07e4d40a40c106e833f408",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0c/72/5ccaf5e423b592ca156cd0d0178c", "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/10/b7/0d8dfe2316fb26ae5bb39f6c5b24",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/86/93/b1c15bb2caa5bbd8a611d70176b0", "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/98/24/86dfc03d0985b358527f1abbaca5",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/73/a0/ced55d043becfbe956b51ca10f18", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/20/82/4544f70ada88097fba6c34c23b77",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/83/50/f30375a1fd32e18b43f81fc8e016", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/be/05/4767c22c4e4821de606a12a9b2a6",
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/27/93/f2ec0018cc303baad498822cbbc7", "build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cc/ce/fd07fcfde4f1a64a776e68c372e6",
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/25/3b86b376c72ed3de5709e28017b5", "build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0b/c0/3b1abad1b5944134705eb123785a",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/45/f1/984c32d20e04123fa1229fa01bc0", "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d6/b5/8f0b3137a8f9006571cf819f39e3",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ee/b2/c4be0770f441d2ffadfd8d929800", "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/38/f1/57af13726ad18b1c71c321d157e8",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4f/3d/fb61c08e9f9de6da3f2a39c01ec0", "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f5/35/e6a7a0a5b6810a77a531bdb78e7a",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c3/2a/bc8cc0304ccd4982645e3129a8b1", "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/94/80/0bb53ea8d7b3243fb308c9c39328",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/81/7a/b5fb51d552c3bbaee9624a22130f", "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9d/c8/cc354640a95c15030d8aa0a6af9a",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ff/f0/5491ac71451f96291d25bd3ec8d7" "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e1/92/0de698b07113f55e90a45b19ad83"
} }

View File

@ -605,6 +605,7 @@
<w>editcontroller</w> <w>editcontroller</w>
<w>editgame</w> <w>editgame</w>
<w>editorconfig</w> <w>editorconfig</w>
<w>effmult</w>
<w>efgrd</w> <w>efgrd</w>
<w>efile</w> <w>efile</w>
<w>efro</w> <w>efro</w>
@ -1822,6 +1823,7 @@
<w>rlock</w> <w>rlock</w>
<w>rmats</w> <w>rmats</w>
<w>rmine</w> <w>rmine</w>
<w>rname</w>
<w>robotparser</w> <w>robotparser</w>
<w>rootc</w> <w>rootc</w>
<w>rootdata</w> <w>rootdata</w>
@ -1829,6 +1831,7 @@
<w>rotatingtree</w> <w>rotatingtree</w>
<w>rowwidget</w> <w>rowwidget</w>
<w>rpcg</w> <w>rpcg</w>
<w>rpings</w>
<w>rppg</w> <w>rppg</w>
<w>rscale</w> <w>rscale</w>
<w>rsdr</w> <w>rsdr</w>

View File

@ -16,6 +16,7 @@ from ba._plugin import PluginSubsystem
from ba._account import AccountSubsystem from ba._account import AccountSubsystem
from ba._meta import MetadataSubsystem from ba._meta import MetadataSubsystem
from ba._ads import AdsSubsystem from ba._ads import AdsSubsystem
from ba._net import NetworkSubsystem
if TYPE_CHECKING: if TYPE_CHECKING:
import ba import ba
@ -237,6 +238,7 @@ class App:
self.ach = AchievementSubsystem() self.ach = AchievementSubsystem()
self.ui = UISubsystem() self.ui = UISubsystem()
self.ads = AdsSubsystem() self.ads = AdsSubsystem()
self.net = NetworkSubsystem()
# Lobby. # Lobby.
self.lobby_random_profile_index: int = 1 self.lobby_random_profile_index: int = 1
@ -411,8 +413,8 @@ class App:
def read_config(self) -> None: def read_config(self) -> None:
"""(internal)""" """(internal)"""
from ba import _appconfig from ba._appconfig import read_config
self._config, self.config_file_healthy = _appconfig.read_config() self._config, self.config_file_healthy = read_config()
def pause(self) -> None: def pause(self) -> None:
"""Pause the game due to a user request or menu popping up. """Pause the game due to a user request or menu popping up.

View File

@ -21,10 +21,17 @@ if TYPE_CHECKING:
DEFAULT_REQUEST_TIMEOUT_SECONDS = 60 DEFAULT_REQUEST_TIMEOUT_SECONDS = 60
class NetworkSubsystem:
"""Network related app subsystem."""
def __init__(self) -> None:
self.region_pings: Dict[str, float] = {}
def is_urllib_network_error(exc: BaseException) -> bool: def is_urllib_network_error(exc: BaseException) -> bool:
"""Is the provided exception a network-related error? """Is the provided exception a network-related error?
This should be passed any exception which resulted from opening or This should be passed an exception which resulted from opening or
reading a urllib Request. It should return True for any errors that reading a urllib Request. It should return True for any errors that
could conceivably arise due to unavailable/poor network connections, could conceivably arise due to unavailable/poor network connections,
firewall/connectivity issues, etc. These issues can often be safely firewall/connectivity issues, etc. These issues can often be safely
@ -53,6 +60,40 @@ def is_urllib_network_error(exc: BaseException) -> bool:
return False return False
def is_udp_network_error(exc: BaseException) -> bool:
"""Is the provided exception a network-related error?
This should be passed an exception which resulted from creating and
using a socket.SOCK_DGRAM type socket. It should return True for any
errors that could conceivably arise due to unavailable/poor network
connections, firewall/connectivity issues, etc. These issues can often
be safely ignored or presented to the user as general
'network-unavailable' states.
"""
import errno
if isinstance(exc, ConnectionRefusedError):
return True
if isinstance(exc, OSError):
if exc.errno == 10051: # Windows unreachable network error.
return True
if exc.errno in {
errno.EADDRNOTAVAIL,
errno.ETIMEDOUT,
errno.EHOSTUNREACH,
errno.ENETUNREACH,
errno.EINVAL,
errno.EPERM,
errno.EACCES,
# Windows 'invalid argument' error.
10022,
# Windows 'a socket operation was attempted to'
# 'an unreachable network' error.
10051,
}:
return True
return False
def get_ip_address_type(addr: str) -> socket.AddressFamily: def get_ip_address_type(addr: str) -> socket.AddressFamily:
"""Return socket.AF_INET6 or socket.AF_INET4 for the provided address.""" """Return socket.AF_INET6 or socket.AF_INET4 for the provided address."""
import socket import socket

View File

@ -27,7 +27,7 @@ from ba._multiteamsession import DEFAULT_TEAM_COLORS, DEFAULT_TEAM_NAMES
from ba._music import do_play_music from ba._music import do_play_music
from ba._net import (master_server_get, master_server_post, from ba._net import (master_server_get, master_server_post,
get_ip_address_type, is_urllib_network_error, get_ip_address_type, is_urllib_network_error,
DEFAULT_REQUEST_TIMEOUT_SECONDS) is_udp_network_error, DEFAULT_REQUEST_TIMEOUT_SECONDS)
from ba._powerup import get_default_powerup_distribution from ba._powerup import get_default_powerup_distribution
from ba._profile import (get_player_profile_colors, get_player_profile_icon, from ba._profile import (get_player_profile_colors, get_player_profile_icon,
get_player_colors) get_player_colors)

View File

@ -633,11 +633,8 @@ class ManualGatherTab(GatherTab):
from_other_thread=True, from_other_thread=True,
) )
except Exception as exc: except Exception as exc:
err_str = str(exc) from ba.internal import is_udp_network_error
if is_udp_network_error(exc):
# FIXME: Should look at exception types here,
# not strings.
if 'Network is unreachable' in err_str:
ba.pushcall(ba.Call( ba.pushcall(ba.Call(
_safe_set_text, self._checking_state_text, _safe_set_text, self._checking_state_text,
ba.Lstr(resource='gatherWindow.' ba.Lstr(resource='gatherWindow.'

View File

@ -303,7 +303,7 @@ class PrivateGatherTab(GatherTab):
try: try:
state = dataclass_from_dict(HostingState, result) state = dataclass_from_dict(HostingState, result)
except Exception: except Exception:
pass ba.print_exception('Got invalid HostingState data')
else: else:
self._debug_server_comm('private party state response errored') self._debug_server_comm('private party state response errored')

View File

@ -219,9 +219,9 @@ class AddrFetchThread(threading.Thread):
sock.close() sock.close()
ba.pushcall(ba.Call(self._call, val), from_other_thread=True) ba.pushcall(ba.Call(self._call, val), from_other_thread=True)
except Exception as exc: except Exception as exc:
from ba.internal import is_udp_network_error
# Ignore expected network errors; log others. # Ignore expected network errors; log others.
import errno if is_udp_network_error(exc):
if isinstance(exc, OSError) and exc.errno == errno.ENETUNREACH:
pass pass
else: else:
ba.print_exception() ba.print_exception()
@ -238,8 +238,6 @@ class PingThread(threading.Thread):
self._call = call self._call = call
def run(self) -> None: def run(self) -> None:
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
ba.app.ping_thread_count += 1 ba.app.ping_thread_count += 1
sock: Optional[socket.socket] = None sock: Optional[socket.socket] = None
try: try:
@ -272,39 +270,12 @@ class PingThread(threading.Thread):
ba.pushcall(ba.Call(self._call, self._address, self._port, ba.pushcall(ba.Call(self._call, self._address, self._port,
ping if accessible else None), ping if accessible else None),
from_other_thread=True) from_other_thread=True)
except ConnectionRefusedError: except Exception as exc:
# Fine, server; sorry we pinged you. Hmph. from ba.internal import is_udp_network_error
pass if is_udp_network_error(exc):
except OSError as exc:
import errno
# Ignore harmless errors.
if exc.errno in {
errno.EHOSTUNREACH, errno.ENETUNREACH, errno.EINVAL,
errno.EPERM, errno.EACCES
}:
pass pass
elif exc.errno == 10022:
# Windows 'invalid argument' error.
pass
elif exc.errno == 10051:
# Windows 'a socket operation was attempted
# to an unreachable network' error.
pass
elif exc.errno == errno.EADDRNOTAVAIL:
if self._port == 0:
# This has happened. Ignore.
pass
elif ba.do_once():
print(f'Got EADDRNOTAVAIL on gather ping'
f' for addr {self._address}'
f' port {self._port}.')
else: else:
ba.print_exception( ba.print_exception('Error on gather ping', once=True)
f'Error on gather ping '
f'(errno={exc.errno})', once=True)
except Exception:
ba.print_exception('Error on gather ping', once=True)
finally: finally:
try: try:
if sock is not None: if sock is not None:

View File

@ -266,6 +266,7 @@
<w>dynamicdata</w> <w>dynamicdata</w>
<w>echidna</w> <w>echidna</w>
<w>edef</w> <w>edef</w>
<w>effmult</w>
<w>efro</w> <w>efro</w>
<w>efrohack</w> <w>efrohack</w>
<w>efrohome</w> <w>efrohome</w>
@ -796,8 +797,10 @@
<w>rgui</w> <w>rgui</w>
<w>richcompare</w> <w>richcompare</w>
<w>rigth</w> <w>rigth</w>
<w>rname</w>
<w>rootwidget</w> <w>rootwidget</w>
<w>rowwidget</w> <w>rowwidget</w>
<w>rpings</w>
<w>rresize</w> <w>rresize</w>
<w>rresult</w> <w>rresult</w>
<w>rscode</w> <w>rscode</w>

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND --> <!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2021-04-27 for Ballistica version 1.6.0 build 20349</em></h4> <h4><em>last updated on 2021-04-28 for Ballistica version 1.6.0 build 20350</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module, <p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p> which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr> <hr>

View File

@ -21,7 +21,7 @@
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't change here. // These are set automatically via script; don't change here.
const int kAppBuildNumber = 20350; const int kAppBuildNumber = 20351;
const char* kAppVersion = "1.6.0"; const char* kAppVersion = "1.6.0";
// Our standalone globals. // Our standalone globals.