From 4655cc7391557d2d4001aef7d9aec547d4c25dd0 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 23 Jun 2020 02:10:34 -0700 Subject: [PATCH] v1.5.10 --- .efrocachemap | 24 +++---- .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 3 + assets/src/ba_data/python/ba/_netutils.py | 35 ++++++++-- assets/src/ba_data/python/ba/modutils.py | 73 ++++++++++++-------- assets/src/ba_data/python/ba/osmusic.py | 7 +- assets/src/ba_data/python/bastd/ui/gather.py | 19 +++-- docs/ba_module.md | 2 +- 8 files changed, 101 insertions(+), 63 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 9b742b51..eb6aa543 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4135,16 +4135,16 @@ "assets/build/windows/x64/vc_redist.x64.exe": "https://files.ballistica.net/cache/ba1/ea/19/8b8787d81abcdce158ba608cd24f", "assets/build/windows/x64/vcruntime140_1d.dll": "https://files.ballistica.net/cache/ba1/11/d8/ff6344b429b00c24d9a1930d4338", "assets/build/windows/x64/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/20/33/0825e11e6518f87ece3009309933", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ef/00/26669a4c745046379f89f9dd14da", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5b/2c/bd7e5d1aa459ae3c0b21e4d057fa", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/da/39/d33b31a44837a70473c2dc4bcd33", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/96/3cc53735853bd6e8d60b433f95a0", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/c5/658f143679fd8f56150357e090af", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/9b/b62d121f0c6fb665a26c7832a015", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/86/8f/59e767e409088cedb70b7ebad514", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5c/10/3356ad1eefadf9902dac526d70f8", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8d/dc/80d1aca955cff4ce0d6e27b67fbd", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0d/76/aa2714c41e4c996c0f47f3e82699", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5d/bc/eed0ece2e4a641f74ec3f2d1bee1", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/75/1e/0bcec9cbe6fcc933249cbfcccb9f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/a1/dbaa655aeffc956c419ecbb3a0f1", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a5/10/3d7cb0d4b13a27574735e2b1aa63", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/00/67/1089a04debbb8b0523c7311780d2", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/57/d17251f72bb763fbdb7741d0da9d", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/e9/44c85334c39d41b2f9ea592de605", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d4/1f/034553946265bacfc722b86d57f8", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/83/2f/350d0e3ffbe1e4a3eca662fc2e1a", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/62/38/6615fedcf4c970ea3dc66147de18", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/13/47/d84222f416e0da118cda7e8862ae", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7f/3e/0cb90e11e701f560fa037604e919", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/34/df/1f16b4633ec30aa50a64016d87b1", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/94/f7/ce16094966391c21be78f541bc2c" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index b97b270f..9299712b 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1385,6 +1385,7 @@ pathlib pathnames pathstonames + pathtmp patsubst pausable pbrowser diff --git a/CHANGELOG.md b/CHANGELOG.md index c170868b..ec5bcf28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ### 1.5.10 (20083) - Streamlined C++ layer bootstrapping process a bit. +- Creating sys scripts via ba.modutils now works properly. +- Custom soundtracks should now work again under Android 10. +- Misc other bug fixes. ### 1.5.9 (20082) - Reduced some hitches when clicking on certain buttons in the UI diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index dc0180c4..08a41f82 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -105,9 +105,11 @@ class ServerCallThread(threading.Thread): self._callback(arg) def run(self) -> None: + # pylint: disable=too-many-branches import urllib.request import urllib.error import json + import http.client from ba import _general try: self._data = _general.utf8_all(self._data) @@ -145,16 +147,35 @@ class ServerCallThread(threading.Thread): response_data = json.loads(raw_data_s) else: raise TypeError(f'invalid responsetype: {self._response_type}') - except (urllib.error.URLError, ConnectionError): - # Server rejected us, broken pipe, etc. It happens. Ignoring. - response_data = None + except Exception as exc: - # Any other error here is unexpected, so let's make a note of it. - print('Exc in ServerCallThread:', exc) - import traceback - traceback.print_exc() + import errno + do_print = False response_data = None + # Ignore common network errors; note unexpected ones. + if isinstance(exc, (urllib.error.URLError, ConnectionError, + http.client.IncompleteRead)): + pass + elif isinstance(exc, OSError): + if exc.errno == 10051: # Windows unreachable network error. + pass + elif exc.errno in [errno.ETIMEDOUT]: + pass + else: + do_print = True + else: + do_print = True + + if do_print: + # Any other error here is unexpected, + # so let's make a note of it, + print(f'Error in ServerCallThread' + f' (response-type={self._response_type},' + f' response-data={response_data}):') + import traceback + traceback.print_exc() + if self._callback is not None: _ba.pushcall(_general.Call(self._run_callback, response_data), from_other_thread=True) diff --git a/assets/src/ba_data/python/ba/modutils.py b/assets/src/ba_data/python/ba/modutils.py index f7645821..a4ec3c0a 100644 --- a/assets/src/ba_data/python/ba/modutils.py +++ b/assets/src/ba_data/python/ba/modutils.py @@ -27,7 +27,7 @@ import os import _ba if TYPE_CHECKING: - from typing import Optional + from typing import Optional, List, Sequence def get_human_readable_user_scripts_path() -> str: @@ -55,18 +55,25 @@ def get_human_readable_user_scripts_path() -> str: return path +def _request_storage_permission() -> bool: + """If needed, requests storage permission from the user (& return true).""" + from ba._lang import Lstr + from ba._enums import Permission + if not _ba.have_permission(Permission.STORAGE): + _ba.playsound(_ba.getsound('error')) + _ba.screenmessage(Lstr(resource='storagePermissionAccessText'), + color=(1, 0, 0)) + _ba.timer(1.0, lambda: _ba.request_permission(Permission.STORAGE)) + return True + return False + + def show_user_scripts() -> None: """Open or nicely print the location of the user-scripts directory.""" - from ba import _lang - from ba._enums import Permission app = _ba.app # First off, if we need permission for this, ask for it. - if not _ba.have_permission(Permission.STORAGE): - _ba.playsound(_ba.getsound('error')) - _ba.screenmessage(_lang.Lstr(resource='storagePermissionAccessText'), - color=(1, 0, 0)) - _ba.request_permission(Permission.STORAGE) + if _request_storage_permission(): return # Secondly, if the dir doesn't exist, attempt to make it. @@ -107,31 +114,37 @@ def create_user_system_scripts() -> None: (for editing and experiment with) """ - app = _ba.app import shutil + app = _ba.app + + # First off, if we need permission for this, ask for it. + if _request_storage_permission(): + return + path = (app.python_directory_user + '/sys/' + app.version) + pathtmp = path + '_tmp' if os.path.exists(path): shutil.rmtree(path) - if os.path.exists(path + '_tmp'): - shutil.rmtree(path + '_tmp') - os.makedirs(path + '_tmp', exist_ok=True) + if os.path.exists(pathtmp): + shutil.rmtree(pathtmp) - # Hmm; shutil.copytree doesn't seem to work nicely on android, - # so lets do it manually. - # NOTE: Should retry this now that we have 3.7 (this note was for 2.7) - src_dir = app.python_directory_app - dst_dir = path + '_tmp' - filenames = os.listdir(app.python_directory_app) - for fname in filenames: - print('COPYING', src_dir + '/' + fname, '->', dst_dir) - shutil.copyfile(src_dir + '/' + fname, dst_dir + '/' + fname) + def _ignore_filter(src: str, names: Sequence[str]) -> Sequence[str]: + del src, names # Unused - print('MOVING', path + '_tmp', path) - shutil.move(path + '_tmp', path) - print( - ('Created system scripts at :\'' + path + - '\'\nRestart Ballistica to use them. (use ba.quit() to exit the game)' - )) + # We simply skip all __pycache__ directories. (the user would have + # to blow them away anyway to make changes; + # See https://github.com/efroemling/ballistica/wiki + # /Knowledge-Nuggets#python-cache-files-gotcha + return ('__pycache__', ) + + print(f'COPYING "{app.python_directory_app}" -> "{pathtmp}".') + shutil.copytree(app.python_directory_app, pathtmp, ignore=_ignore_filter) + + print(f'MOVING "{pathtmp}" -> "{path}".') + shutil.move(pathtmp, path) + print(f"Created system scripts at :'{path}" + f"'\nRestart {_ba.appname()} to use them." + f' (use ba.quit() to exit the game)') if app.platform == 'android': print('Note: the new files may not be visible via ' 'android-file-transfer until you restart your device.') @@ -144,9 +157,9 @@ def delete_user_system_scripts() -> None: path = (app.python_directory_user + '/sys/' + app.version) if os.path.exists(path): shutil.rmtree(path) - print( - 'User system scripts deleted.\nRestart Ballistica to use internal' - ' scripts. (use ba.quit() to exit the game)') + print(f'User system scripts deleted.\n' + f'Restart {_ba.appname()} to use internal' + f' scripts. (use ba.quit() to exit the game)') else: print('User system scripts not found.') diff --git a/assets/src/ba_data/python/ba/osmusic.py b/assets/src/ba_data/python/ba/osmusic.py index 0b7c4a36..e188bebf 100644 --- a/assets/src/ba_data/python/ba/osmusic.py +++ b/assets/src/ba_data/python/ba/osmusic.py @@ -123,6 +123,7 @@ class _PickFolderSongThread(threading.Thread): def run(self) -> None: from ba import _lang from ba._general import Call + do_print_error = True try: _ba.set_thread_name('BA_PickFolderSongThread') all_files: List[str] = [] @@ -134,14 +135,16 @@ class _PickFolderSongThread(threading.Thread): all_files.insert(random.randrange(len(all_files) + 1), root + '/' + fname) if not all_files: - raise Exception( + do_print_error = False + raise RuntimeError( _lang.Lstr(resource='internal.noMusicFilesInFolderText'). evaluate()) _ba.pushcall(Call(self._callback, all_files, None), from_other_thread=True) except Exception as exc: from ba import _error - _error.print_exception() + if do_print_error: + _error.print_exception() try: err_str = str(exc) except Exception: diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 464f27ee..8edcdd24 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -435,19 +435,16 @@ class GatherWindow(ba.Window): sock.connect(('8.8.8.8', 80)) val = sock.getsockname()[0] sock.close() - # val = ([ - # (s.connect(('8.8.8.8', 80)), - # s.getsockname()[0], - # s.close()) for s in - # [socket.socket(socket.AF_INET, - # socket.SOCK_DGRAM)] - # ][0][1]) ba.pushcall(ba.Call(self._call, val), from_other_thread=True) - except Exception: - # FIXME: Should filter out expected errors and - # report others here. - ba.print_exception() + except Exception as exc: + # Ignore expected network errors; log others. + import errno + if (isinstance(exc, OSError) + and exc.errno == errno.ENETUNREACH): + pass + else: + ba.print_exception() AddrFetchThread(ba.WeakCall( self._internet_fetch_local_addr_cb)).start() diff --git a/docs/ba_module.md b/docs/ba_module.md index 74d484c8..488ff5a7 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

last updated on 2020-06-22 for Ballistica version 1.5.9 build 20081

+

last updated on 2020-06-23 for Ballistica version 1.5.10 build 20084

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 let me know. Happy modding!